[IOMultiplexerV2] alpha
authorpk910 <philipp@zoelle1.de>
Sun, 2 Mar 2014 20:50:24 +0000 (21:50 +0100)
committerpk910 <philipp@zoelle1.de>
Mon, 3 Mar 2014 16:07:19 +0000 (17:07 +0100)
59 files changed:
.gitignore [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
autogen.sh [new file with mode: 0644]
configure.ac [new file with mode: 0644]
src/.gitignore [new file with mode: 0644]
src/IODNSEngine_cares.c [deleted file]
src/IODNSEngine_default.c [deleted file]
src/IODNSLookup.c [deleted file]
src/IODNSLookup.h [deleted file]
src/IOGarbageCollector.c [deleted file]
src/IOGarbageCollector.h [deleted file]
src/IOHandler.c [deleted file]
src/IOHandler.h [deleted file]
src/IOHandler/.gitignore [new file with mode: 0644]
src/IOHandler/IODNSAddress.struct.h [new file with mode: 0644]
src/IOHandler/IODNSEngine_cares.c [new file with mode: 0644]
src/IOHandler/IODNSEngine_default.c [new file with mode: 0644]
src/IOHandler/IODNSLookup.c [new file with mode: 0644]
src/IOHandler/IODNSLookup.h [new file with mode: 0644]
src/IOHandler/IOEngine_epoll.c [new file with mode: 0644]
src/IOHandler/IOEngine_kevent.c [new file with mode: 0644]
src/IOHandler/IOEngine_select.c [new file with mode: 0644]
src/IOHandler/IOEngine_win32.c [new file with mode: 0644]
src/IOHandler/IOGarbageCollector.c [new file with mode: 0644]
src/IOHandler/IOGarbageCollector.h [new file with mode: 0644]
src/IOHandler/IOHandler.c [new file with mode: 0644]
src/IOHandler/IOHandler.h [new file with mode: 0644]
src/IOHandler/IOHandler_config.h [new file with mode: 0644]
src/IOHandler/IOInternal.h [new file with mode: 0644]
src/IOHandler/IOLog.c [new file with mode: 0644]
src/IOHandler/IOLog.h [new file with mode: 0644]
src/IOHandler/IOSockets.c [new file with mode: 0644]
src/IOHandler/IOSockets.h [new file with mode: 0644]
src/IOHandler/IOTimer.c [new file with mode: 0644]
src/IOHandler/IOTimer.h [new file with mode: 0644]
src/IOHandler/Makefile.am [new file with mode: 0644]
src/IOHandler/compat/inet.c [new file with mode: 0644]
src/IOHandler/compat/inet.h [new file with mode: 0644]
src/IOHandler/compat/utime.c [new file with mode: 0644]
src/IOHandler/compat/utime.h [new file with mode: 0644]
src/IOHandler_test/Makefile.am [new file with mode: 0644]
src/IOHandler_test/socket/.gitignore [new file with mode: 0644]
src/IOHandler_test/socket/Makefile.am [new file with mode: 0644]
src/IOHandler_test/socket/iotest.c [new file with mode: 0644]
src/IOHandler_test/timer/Makefile.am [new file with mode: 0644]
src/IOHandler_test/timer/iotest.c [new file with mode: 0644]
src/IOInternal.h [deleted file]
src/IOLog.c [deleted file]
src/IOLog.h [deleted file]
src/IOSockets.c [deleted file]
src/IOSockets.h [deleted file]
src/IOTimer.c [deleted file]
src/IOTimer.h [deleted file]
src/Makefile.am [new file with mode: 0644]
src/compat/utime.c [deleted file]
src/test/socket/Makefile [deleted file]
src/test/socket/iotest.c [deleted file]
src/test/timer/Makefile [deleted file]
src/test/timer/iotest.c [deleted file]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..f134593
--- /dev/null
@@ -0,0 +1,18 @@
+autom4te.cache
+m4
+aclocal.m4
+config.guess
+config.h
+config.h.in
+config.log
+config.status
+config.sub
+configure
+depcomp
+install-sh
+libtool
+ltmain.sh
+Makefile
+Makefile.in
+missing
+stamp-h1
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..92ae850
--- /dev/null
@@ -0,0 +1,3 @@
+##Process this file with automake to create Makefile.in
+ACLOCAL_AMFLAGS = -I m4
+SUBDIRS = src
diff --git a/autogen.sh b/autogen.sh
new file mode 100644 (file)
index 0000000..01c075c
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+echo "Generating configure files... may take a while."
+
+autoreconf --install --force && \
+  echo "Preparing was successful if there was no error messages above." && \
+  echo "Now type:" && \
+  echo "  ./configure && make"  && \
+  echo "Run './configure --help' for more information"
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..bd831bc
--- /dev/null
@@ -0,0 +1,52 @@
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ([2.67])
+AC_INIT([IOMultiplexer], [2.0], [iohandler@pk910.de], [pk910], [http://pk910.de])
+AC_PREFIX_DEFAULT([~/iotest])
+AC_CONFIG_MACRO_DIR([m4])
+AM_INIT_AUTOMAKE([foreign])
+#AM_SILENT_RULES([yes])
+AC_CONFIG_HEADERS([config.h])
+
+#LT_INIT([disable-static])
+
+AC_MSG_RESULT($MODULES)
+AC_SUBST(MODULES)
+
+# Checks for programs.
+AC_PROG_AWK
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_MAKE_SET
+AC_PROG_RANLIB
+
+AC_ARG_ENABLE([debug],
+  [AS_HELP_STRING([--enable-debug], [debug mode (compile using -O0 -Wall -Wshadow -Werror)])],
+  [CFLAGS='-g -O0 -Wall -Wshadow -Werror'],
+  [CFLAGS='-g -O2']
+)
+
+# Checks for libraries.
+
+CFLAGS="$CFLAGS -D_GNU_SOURCE"
+
+AC_FUNC_MALLOC
+AC_CHECK_FUNCS([usleep select socket inet_pton inet_ntop])
+AC_CHECK_HEADERS([fcntl.h sys/socket.h sys/select.h sys/time.h sys/types.h unistd.h windows.h winsock2.h errno.h sys/epoll.h sys/event.h])
+
+AC_CHECK_LIB(ws2_32, main, [ LIBS="$LIBS -lws2_32" ], [])
+AC_CHECK_LIB(ssl, SSL_read, [
+  AC_CHECK_LIB(crypto, X509_new, [
+    AC_CHECK_HEADERS(openssl/ssl.h openssl/err.h openssl/rand.h, [
+      LIBS="$LIBS -lssl -lcrypto"
+    ])
+  ])
+])
+AC_CHECK_LIB(pthread, pthread_create, [
+  AC_CHECK_HEADERS(pthread.h, [
+    LIBS="$LIBS -lpthread"
+  ])
+])
+
+AC_CONFIG_FILES([Makefile src/Makefile src/IOHandler/Makefile src/IOHandler_test/Makefile src/IOHandler_test/socket/Makefile src/IOHandler_test/timer/Makefile])
+AC_OUTPUT
diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644 (file)
index 0000000..3dda729
--- /dev/null
@@ -0,0 +1,2 @@
+Makefile.in
+Makefile
diff --git a/src/IODNSEngine_cares.c b/src/IODNSEngine_cares.c
deleted file mode 100644 (file)
index 0852470..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/* IODNSEngine_cares.c - IOMultiplexer
- * Copyright (C) 2014  Philipp Kreil (pk910)
- * 
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License 
- * along with this program. If not, see <http://www.gnu.org/licenses/>. 
- */
-#define _IOHandler_internals
-#include "IOInternal.h"
-#include "IOHandler.h"
-#include "IODNSHandler.h"
-
-static int dnsengine_cares_init() {
-       /* TODO */
-    return 0;
-}
-
-static void dnsengine_cares_stop() {
-       /* TODO */
-}
-
-static void dnsengine_cares_add(struct _IODNSQuery *iodns) {
-    /* TODO */
-}
-
-static void dnsengine_cares_remove(struct _IODNSQuery *iodns) {
-    /* TODO */
-}
-
-static void dnsengine_cares_loop() {
-    /* TODO */
-}
-
-struct IODNSEngine dnsengine_cares = {
-    .name = "c-ares",
-    .init = dnsengine_cares_init,
-       .stop = dnsengine_cares_stop,
-    .add = dnsengine_cares_add,
-    .remove = dnsengine_cares_remove,
-    .loop = dnsengine_cares_loop,
-};
diff --git a/src/IODNSEngine_default.c b/src/IODNSEngine_default.c
deleted file mode 100644 (file)
index 07e46c6..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-/* IODNSEngine_default.c - IOMultiplexer
- * Copyright (C) 2014  Philipp Kreil (pk910)
- * 
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License 
- * along with this program. If not, see <http://www.gnu.org/licenses/>. 
- */
-#define _IOHandler_internals
-#include "IOInternal.h"
-#include "IOHandler.h"
-#include "IODNSHandler.h"
-
-#ifdef HAVE_PTHREAD_H
-static pthread_t *iodns_thread;
-static int iodns_thread_running = 1;
-
-static pthread_cond_t iodns_cond;
-static pthread_mutex_t iodns_sync2;
-#endif
-static int iodns_loop_blocking = 0;
-
-static void iodns_process_queries();
-
-static void dnsengine_worker_main(void *arg) {
-       struct _IODNSQuery *query;
-       while(iodns_thread_running) {
-               IOSYNCHRONIZE(iodns_sync);
-               for(query = iodnsquery_first; query; query = query->next) {
-                       if((query->flags & IODNSFLAG_RUNNING))
-                               break;
-               }
-               IODESYNCHRONIZE(iodns_sync);
-               if(!query)
-                       pthread_cond_wait(&iodns_cond, &iodns_sync2);
-               
-               if(iodns_thread_running)
-                       iodns_process_queries();
-       }
-}
-
-static int dnsengine_default_init() {
-       #ifdef HAVE_PTHREAD_H
-       /* create worker thread */
-       pthread_cond_init(&iodns_cond, NULL);
-       IOTHREAD_MUTEX_INIT(iodns_sync2);
-       
-       iodns_thread_running = 1;
-       
-       int thread_err;
-       thread_err = pthread_create(&iodns_thread, NULL, dnsengine_worker_main, NULL);
-       if(thread_err) {
-               iolog_trigger(IOLOG_ERROR, "could not create pthread in %s:%d (Returned: %i)", __FILE__, __LINE__, thread_err);
-               iodns_loop_blocking = 1;
-               iodns_thread = NULL;
-               iodns_thread_running = 0;
-       }
-       #else
-       iodns_loop_blocking = 1;
-       #endif
-    return 1;
-}
-
-static void dnsengine_default_stop() {
-       #ifdef HAVE_PTHREAD_H
-       if(iodns_thread_running) {
-               iodns_thread_running = 0;
-               IOSYNCHRONIZE(iodns_sync2);
-               pthread_cond_signal(&iodns_cond);
-               IODESYNCHRONIZE(iodns_sync2);
-               pthread_join(iodns_thread, NULL);
-       }
-       #endif
-}
-
-static void dnsengine_default_add(struct _IODNSQuery *iodns) {
-    #ifdef HAVE_PTHREAD_H
-       if(iodns_thread_running) {
-               IOSYNCHRONIZE(iodns_sync2);
-               pthread_cond_signal(&iodns_cond);
-               IODESYNCHRONIZE(iodns_sync2);
-       }
-       #endif
-}
-
-static void dnsengine_default_remove(struct _IODNSQuery *iodns) {
-    /* unused */
-}
-
-static void dnsengine_default_loop() {
-    if(iodns_loop_blocking)
-               iodns_process_queries();
-}
-
-static void iodns_process_queries() {
-       enum IODNSEventType querystate;
-    struct addrinfo hints, *res, *next_res;
-    struct _IODNSQuery *iodns, *next_iodns;
-    struct IODNSResult *dnsresult;
-       iodns_process_queries_start:
-       IOSYNCHRONIZE(iodns_sync);
-    for(iodns = first_dnsquery; iodns; iodns = next_iodns) {
-        next_iodns = iodns->next;
-               
-               if(!(iodns->flags & IODNSFLAG_RUNNING))
-                       continue;
-               if((iodns->flags & IODNSFLAG_PROCESSING))
-                       continue;
-               
-               IODESYNCHRONIZE(iodns_sync);
-               
-        querystate = IODNSEVENT_FAILED;
-        
-        if((iodns->type & IODNS_FORWARD)) {
-            memset (&hints, 0, sizeof (hints));
-            hints.ai_family = PF_UNSPEC;
-            hints.ai_socktype = SOCK_STREAM;
-            hints.ai_flags |= AI_CANONNAME;
-            if (!getaddrinfo(iodns->request.host, NULL, &hints, &res)) {
-                while (res) {
-                    switch (res->ai_family) {
-                    case AF_INET:
-                        if((iodns->type & IODNS_RECORD_A)) {
-                            dnsresult = malloc(sizeof(*dnsresult));
-                            dnsresult->type = IODNS_RECORD_A;
-                            dnsresult->result.addr.addresslen = res->ai_addrlen;
-                            dnsresult->result.addr.address = malloc(dnsresult->addresslen);
-                            memcpy(dnsresult->address, res->ai_addr, dnsresult->addresslen);
-                            dnsresult->next = iodns->result;
-                            iodns->result = dnsresult;
-                            querystate = IODNSEVENT_SUCCESS;
-                        }
-                        break;
-                    case AF_INET6:
-                        if((iodns->type & IODNS_RECORD_AAAA)) {
-                            dnsresult = malloc(sizeof(*dnsresult));
-                            dnsresult->type = IODNS_RECORD_AAAA;
-                            dnsresult->result.addr.addresslen = res->ai_addrlen;
-                            dnsresult->result.addr.address = malloc(dnsresult->addresslen);
-                            memcpy(dnsresult->address, res->ai_addr, dnsresult->addresslen);
-                            dnsresult->next = iodns->result;
-                            iodns->result = dnsresult;
-                            querystate = IODNSEVENT_SUCCESS;
-                        }
-                        break;
-                    }
-                    next_res = res->ai_next;
-                    freeaddrinfo(res);
-                    res = next_res;
-                }
-            }
-        }
-               IOSYNCHRONIZE(iodns_sync);
-               if(!(iodns->flags & IODNSFLAG_RUNNING)) {
-                       iodns_free_result(iodns->result);
-                       _free_dnsquery(iodns);
-                       IODESYNCHRONIZE(iodns_sync);
-                       goto iodns_process_queries_start;
-               }
-               iodns->flags &= ~(IODNSFLAG_PROCESSING | IODNSFLAG_RUNNING);
-               IODESYNCHRONIZE(iodns_sync);
-               iodns_event_callback(iodns, querystate);
-               goto iodns_process_queries_start;
-    }
-}
-
-struct IODNSEngine dnsengine_default = {
-    .name = "default",
-    .init = dnsengine_default_init,
-       .stop = dnsengine_default_stop,
-    .add = dnsengine_default_add,
-    .remove = dnsengine_default_remove,
-    .loop = dnsengine_default_loop,
-};
diff --git a/src/IODNSLookup.c b/src/IODNSLookup.c
deleted file mode 100644 (file)
index 5497553..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-/* IODNSLookup.c - IOMultiplexer
- * Copyright (C) 2014  Philipp Kreil (pk910)
- * 
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License 
- * along with this program. If not, see <http://www.gnu.org/licenses/>. 
- */
-#define _IOHandler_internals
-#include "IOInternal.h"
-#include "IOHandler.h"
-#include "IODNSLookup.h"
-#include "IOLog.h"
-#include "IOSockets.h"
-
-#ifdef HAVE_PTHREAD_H
-pthread_mutex_t iodns_sync;
-#endif
-
-struct _IODNSQuery *iodnsquery_first = NULL;
-struct _IODNSQuery *iodnsquery_last = NULL;
-
-struct IODNSEngine *dnsengine = NULL;
-
-static void iodns_init_engine() {
-       if(dnsengine)
-               return;
-       //try DNS engines
-       if(dnsengine_cares.init && dnsengine_cares.init())
-               dnsengine = &dnsengine_cares;
-       else if(dnsengine_default.init && dnsengine_default.init())
-               dnsengine = &dnsengine_default;
-       else {
-               iohandler_log(IOLOG_FATAL, "found no useable IO DNS engine");
-               return;
-       }
-       iohandler_log(IOLOG_DEBUG, "using %s IODNS engine", dnsengine->name);
-}
-
-void _init_iodns() {
-       IOTHREAD_MUTEX_INIT(iodns_sync);
-       iodns_init_engine();
-}
-
-struct _IODNSQuery *_create_dnsquery() {
-       struct _IODNSQuery *query = calloc(1, sizeof(*query));
-       if(!query) {
-               iolog_trigger(IOLOG_ERROR, "could not allocate memory for _IODNSQuery in %s:%d", __FILE__, __LINE__);
-               return NULL;
-       }
-       IOSYNCHRONIZE(iodns_sync);
-       if(iodnsquery_last)
-               iodnsquery_last->next = query;
-       else
-               iodnsquery_first = query;
-       query->prev = iodnsquery_last;
-       iodnsquery_last = query;
-       IODESYNCHRONIZE(iodns_sync);
-       return query;
-}
-
-void _start_dnsquery(struct _IODNSQuery *query) {
-       IOSYNCHRONIZE(iodns_sync);
-       query->flags |= IODNSFLAG_RUNNING;
-       dnsengine->add(query);
-       IODESYNCHRONIZE(iodns_sync);
-}
-
-void _free_dnsquery(struct _IODNSQuery *query) {
-       IOSYNCHRONIZE(iodns_sync);
-       if(query->prev)
-               query->prev->next = query->next;
-       else
-               iodnsquery_first = query->next;
-       if(query->next)
-               query->next->prev = query->prev;
-       else
-               iodnsquery_last = query->prev;
-       IODESYNCHRONIZE(iodns_sync);
-       if((query->type & IODNS_REVERSE) && query->request.addr.address)
-               free(query->request.addr.address);
-       free(query);
-}
-
-void _stop_dnsquery(struct _IODNSQuery *query) {
-       IOSYNCHRONIZE(iodns_sync);
-       if((query->flags & IODNSFLAG_RUNNING)) {
-               query->flags &= ~IODNSFLAG_RUNNING;
-               dnsengine->remove(query);
-       }
-       if(!(query->flags & IODNSFLAG_PROCESSING))
-               _free_dnsquery(query);
-       IODESYNCHRONIZE(iodns_sync);
-}
-
-void iodns_event_callback(struct _IODNSQuery *query, enum IODNSEventType state) {
-       if((query->flags & IODNSFLAG_PARENT_PUBLIC)) {
-               struct IODNSQuery *descriptor = query->parent;
-               struct IODNSEvent event;
-               event.type = state;
-               event.query = descriptor;
-               event.result = query->result;
-               
-               descriptor->parent = NULL;
-               _stop_dnsquery(query);
-               
-               if(descriptor->callback)
-                       descriptor->callback(&event);
-               
-               iogc_add(descriptor);
-       } else if((query->flags & IODNSFLAG_PARENT_SOCKET)) {
-               struct IODNSEvent event;
-               event.type = state;
-               event.query = NULL;
-               event.result = query->result
-               void *parent = query->parent;
-               
-               _stop_dnsquery(query);
-               iosocket_lookup_callback(parent, &event);
-               
-       }
-}
-
-void iodns_poll() {
-       if(dnsengine)
-               dnsengine.loop();
-}
-
-/* public functions */
-
-struct IODNSQuery *iodns_getaddrinfo(char *hostname, int records, iodns_callback *callback) {
-       if(!(records & IODNS_FORWARD) || !hostname || !callback)
-               return NULL;
-       
-       struct IODNSQuery *descriptor = calloc(1, sizeof(*descriptor));
-       if(!descriptor) {
-               iolog_trigger(IOLOG_ERROR, "could not allocate memory for IODNSQuery in %s:%d", __FILE__, __LINE__);
-               return NULL;
-       }
-       
-       struct _IODNSQuery *query = _create_dnsquery();
-       if(!query) {
-               free(descriptor);
-               return NULL
-       }
-       
-       query->parent = descriptor;
-       query->flags |= IODNSFLAG_PARENT_PUBLIC;
-       descriptor->query = query;
-       
-       query->request.host = strdup(hostname);
-       query->type = (records & IODNS_FORWARD);
-       
-       descriptor->callback = callback;
-       
-       _start_dnsquery(query);
-       return descriptor;
-}
-
-struct IODNSQuery *iodns_getnameinfo(const struct sockaddr *addr, socklen_t addrlen, iodns_callback *callback) {
-       if(!addr || !callback)
-               return NULL;
-       
-       struct IODNSQuery *descriptor = calloc(1, sizeof(*descriptor));
-       if(!descriptor) {
-               iolog_trigger(IOLOG_ERROR, "could not allocate memory for IODNSQuery in %s:%d", __FILE__, __LINE__);
-               return NULL;
-       }
-       
-       struct _IODNSQuery *query = _create_dnsquery();
-       if(!query) {
-               free(descriptor);
-               return NULL
-       }
-       
-       query->parent = descriptor;
-       query->flags |= IODNSFLAG_PARENT_PUBLIC;
-       descriptor->query = query;
-       
-       query->type = IODNS_RECORD_PTR;
-       query->request.addr.addresslen = addrlen;
-       query->request.addr.address = malloc(addrlen);
-       if(!query->request.addr.address) {
-               iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__);
-               _free_dnsquery(query);
-               free(descriptor);
-               return NULL;
-       }
-       memcpy(query->request.addr.address, addr, addrlen);
-       
-       descriptor->callback = callback;
-       
-       _start_dnsquery(query);
-       return descriptor;
-}
-
-void iodns_abort(struct IODNSQuery *descriptor) {
-       if(!descriptor)
-               return;
-       
-       struct _IODNSQuery *query = descriptor->query;
-       if(!query) {
-               iolog_trigger(IOLOG_WARNING, "called iodns_abort for destroyed IODNSQuery in %s:%d", __FILE__, __LINE__);
-               return;
-       }
-       
-       _stop_dnsquery(query)
-}
-
-void iodns_free_result(struct IODNSResult *result) {
-       struct IODNSResult *next;
-       for(;result;result = next) {
-               next = result->next;
-               
-               if((result->type & IODNS_FORWARD)) {
-                       if(result->result.addr.address)
-                               free(result->result.addr.address);
-               }
-               if((result->type & IODNS_REVERSE)) {
-                       if(result->result.host)
-                               free(result->result.host);
-               }
-               free(result);
-       }
-}
-
diff --git a/src/IODNSLookup.h b/src/IODNSLookup.h
deleted file mode 100644 (file)
index 4235297..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-/* IODNSLookup.h - IOMultiplexer v2
- * Copyright (C) 2014  Philipp Kreil (pk910)
- * 
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License 
- * along with this program. If not, see <http://www.gnu.org/licenses/>. 
- */
-#ifndef _IODNSLookup_h
-#define _IODNSLookup_h
-#ifndef _IOHandler_internals
-#include "IOHandler.h"
-#else
-
-extern struct IODNSEngine dnsengine_cares;
-extern struct IODNSEngine dnsengine_default;
-
-#ifdef HAVE_PTHREAD_H
-extern pthread_mutex_t iodns_sync;
-#endif
-
-struct IODNSAddress;
-
-#define IODNSFLAG_RUNNING        0x01
-#define IODNSFLAG_PROCESSING     0x02
-#define IODNSFLAG_PARENT_PUBLIC  0x04
-#define IODNSFLAG_PARENT_SOCKET  0x08
-
-struct _IODNSQuery {
-       void *query;
-       
-       unsigned int flags : 8;
-       unsigned int type : 8;
-    union {
-               struct IODNSAddress addr;
-               char *host;
-       } request;
-       
-       struct IODNSResult *result;
-       
-       void *parent;
-       
-       struct _IODNSQuery *next, *prev;
-};
-
-struct IODNSEngine {
-    const char *name;
-    int (*init)();
-       void (*stop)();
-    void (*add)(struct _IODNSQuery *query);
-    void (*remove)(struct _IODNSQuery *query);
-    void (*loop)();
-};
-
-void _init_iodns();
-void _stop_iodns();
-struct _IODNSQuery *_create_dnsquery();
-void _start_dnsquery(struct _IODNSQuery *query);
-void _stop_dnsquery(struct _IODNSQuery *query);
-
-/* call only from engines! */
-void _free_dnsquery(struct _IODNSQuery *query)
-void iodns_event_callback(struct _IODNSQuery *query, enum IODNSEventType state);
-
-void iodns_poll();
-
-#endif
-
-#define IODNS_CALLBACK(NAME) void NAME(struct IODNSEvent *event)
-typedef IODNS_CALLBACK(iodns_callback);
-
-enum IODNSEventType {
-    IODNSEVENT_SUCCESS,
-    IODNSEVENT_FAILED
-};
-
-#define IODNS_RECORD_A    0x01
-#define IODNS_RECORD_AAAA 0x02
-#define IODNS_RECORD_PTR  0x04
-
-#define IODNS_FORWARD     0x03
-#define IODNS_REVERSE     0x04
-
-struct IODNSAddress {
-       size_t addresslen;
-       struct sockaddr *address;
-};
-
-struct IODNSQuery {
-       void *query;
-       
-    iodns_callback *callback;
-    void *data;
-};
-
-struct IODNSResult {
-    unsigned int type : 8;
-    union {
-               struct IODNSAddress addr;
-               char *host;
-       } result;
-    struct IODNSResult *next;
-};
-
-struct IODNSEvent {
-    enum IODNSEventType type;
-    struct IODNSQuery *query;
-       struct IODNSResult *result;
-};
-
-struct IODNSQuery *iodns_getaddrinfo(char *hostname, int records, iodns_callback *callback);
-struct IODNSQuery *iodns_getnameinfo(const struct sockaddr *addr, socklen_t addrlen, iodns_callback *callback);
-void iodns_abort(struct IODNSQuery *query);
-
-void iodns_free_result(struct IODNSResult *result);
-
-#endif
diff --git a/src/IOGarbageCollector.c b/src/IOGarbageCollector.c
deleted file mode 100644 (file)
index 363d816..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/* IOGarbageCollector.c - IOMultiplexer v2
- * Copyright (C) 2014  Philipp Kreil (pk910)
- * 
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License 
- * along with this program. If not, see <http://www.gnu.org/licenses/>. 
- */
-#define _IOHandler_internals
-#include "IOInternal.h"
-#include "IOHandler.h"
-#include "IOGarbageCollector.h"
-
-#define timeval_is_bigger(x,y) ((x.tv_sec > y.tv_sec) || (x.tv_sec == y.tv_sec && x.tv_usec > y.tv_usec))
-#define timeval_is_smaler(x,y) ((x.tv_sec < y.tv_sec) || (x.tv_sec == y.tv_sec && x.tv_usec < y.tv_usec))
-
-static struct IOGCObject {
-       void *object;
-       iogc_free *free_callback;
-       struct timeval timeout;
-       
-       struct IOGCObject *next;
-};
-
-#ifdef HAVE_PTHREAD_H
-static pthread_mutex_t iogc_sync;
-#endif
-
-static int iogc_enabled = 1;
-static struct timeval iogc_timeout;
-static struct IOGCObject *first_object = NULL, *last_object = NULL;
-
-void iogc_init() {
-       IOTHREAD_MUTEX_INIT(iogc_sync);
-       iogc_timeout.tv_usec = 0;
-       iogc_timeout.tv_sec = 10;
-}
-
-
-void iohandler_set_gc(int enabled) {
-       if(enabled)
-               iogc_enabled = 1;
-       else
-               iogc_enabled = 0;
-}
-
-void iogc_add(void *object) {
-       iogc_add_callback(object, NULL);
-}
-
-void iogc_add_callback(void *object, iogc_free *free_callback) {
-       if(!iogc_enabled) {
-               if(free_callback)
-                       free_callback(object);
-               else
-                       free(object);
-               return;
-       }
-       struct IOGCObject *obj = malloc(sizeof(*obj));
-    if(!obj) {
-        iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOGCObject in %s:%d", __FILE__, __LINE__);
-               if(free_callback)
-                       free_callback(object);
-               else
-                       free(object);
-        return;
-    }
-       obj->object = object;
-       obj->free_callback = free_callback;
-       gettimeofday(&obj->timeout, NULL);
-       
-}
-
-void iogc_exec() {
-       struct timeval ctime;
-       gettimeofday(&ctime, NULL);
-       
-       struct IOGCObject *obj, *next_obj;
-       for(obj = objects; obj; obj = next_obj) {
-               if(timeval_is_smaler(obj->timeout, ctime)) {
-                       next_obj = obj->next;
-                       if(obj->free_callback)
-                               obj->free_callback(obj->object);
-                       else
-                               free(obj->object);
-                       free(obj);
-               } else {
-                       objects = obj;
-                       break;
-               }
-       }
-}
diff --git a/src/IOGarbageCollector.h b/src/IOGarbageCollector.h
deleted file mode 100644 (file)
index d1e848b..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/* IOGarbageCollector.h - IOMultiplexer v2
- * Copyright (C) 2014  Philipp Kreil (pk910)
- * 
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License 
- * along with this program. If not, see <http://www.gnu.org/licenses/>. 
- */
-#ifndef _IOGarbageCollector_h
-#define _IOGarbageCollector_h
-#ifndef _IOHandler_internals
-#include "IOHandler.h"
-#else
-
-void iogc_init();
-void iogc_exec();
-
-#endif
-#endif
diff --git a/src/IOHandler.c b/src/IOHandler.c
deleted file mode 100644 (file)
index 87e5739..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-/* IOHandler.c - IOMultiplexer v2
- * Copyright (C) 2014  Philipp Kreil (pk910)
- * 
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License 
- * along with this program. If not, see <http://www.gnu.org/licenses/>. 
- */
-#define _IOHandler_internals
-#include "IOInternal.h"
-#include "IOHandler.h"
-
-#include "IOLog.h"
-#include "IOGarbageCollector.h"
-#include "IOTimer.h"
-#include "IODNSLookup.h"
-
-/* compat */
-#include "compat/usleep.c"
-
-#ifdef HAVE_PTHREAD_H
-static pthread_mutex_t iothread_sync;
-#ifdef WIN32
-#define pthread_self_tid() pthread_self().p
-#else
-#define pthread_self_tid() pthread_self()
-#endif
-
-#endif
-
-static struct IOHandlerThread {
-       unsigned int id;
-       unsigned int main : 1;
-       unsigned int run : 1;
-       unsigned int shutdown : 1;
-       #ifdef HAVE_PTHREAD_H
-       static pthread_t *thread;
-       #endif
-       struct IOHandlerThread *next;
-}
-
-static int iohandler_running = 0;
-static int iohandler_treads = 1;
-static struct IOHandlerThread *threads;
-
-void iohandler_init() {
-       IOTHREAD_MUTEX_INIT(iothread_sync);
-       
-       iolog_init();
-       iogc_init();
-       
-       _init_timers();
-       _init_iodns();
-       _init_sockets();
-       
-       iohandler_running = 1;
-}
-
-void iohandler_set_threads(int threadcount) {
-       iohandler_treads = threadcount;
-}
-
-void iohandler_stop() {
-       iohandler_treads = 0;
-}
-
-#ifdef HAVE_PTHREAD_H
-static void iohandler_start_worker() {
-       struct IOHandlerThread *thread = calloc(1, sizeof(*thread));
-    if(!thread) {
-        iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOHandlerThread in %s:%d", __FILE__, __LINE__);
-        return;
-    }
-       struct IOHandlerThread *cthread;
-       for(cthread = threads; cthread; cthread = cthread->next) {
-               if(cthread->next == NULL) {
-                       cthread->next = thread;
-                       break;
-               }
-       }
-       
-       thread->run = 1;
-       
-       int thread_err;
-       thread_err = pthread_create(&thread->thread, NULL, iohandler_worker, thread);
-       if(thread_err) {
-               cthread->next = NULL;
-               iolog_trigger(IOLOG_ERROR, "could not create pthread in %s:%d (Returned: %i)", __FILE__, __LINE__, thread_err);
-       }
-}
-#endif
-
-static void iohandler_worker(void *tptr) {
-       struct IOHandlerThread *thread = tptr;
-       
-       #ifdef HAVE_PTHREAD_H
-       if(!thread->main) {
-               thread->id = pthread_self_tid();
-       }
-       #endif
-       
-       while(!thread->shutdown) { // endless loop
-               if(thread->main && iohandler_treads != iohandler_running) {
-                       IOSYNCHRONIZE(iothread_sync);
-                       #ifdef HAVE_PTHREAD_H
-                       int i;
-                       if(iohandler_treads > iohandler_running) {
-                               for(i = 0; i < (iohandler_treads - iohandler_running); i++)
-                                       iohandler_start_worker();
-                       }
-                       if(iohandler_treads < iohandler_running) {
-                               struct IOHandlerThread *cthread;
-                               for(i = 0; i < (iohandler_running - iohandler_treads); i++) {
-                                       for(cthread = threads; cthread; cthread = cthread->next) {
-                                               if(cthread->main)
-                                                       continue;
-                                               cthread->shutdown = 1;
-                                               iolog_trigger(IOLOG_ERROR, "Thread %d marked for shutdown.", cthread->id);
-                                       }
-                                       if(cthread)
-                                               iohandler_running--;
-                               }
-                       }
-                       #endif
-                       if(iohandler_treads == 0) {
-                               #ifdef HAVE_PTHREAD_H
-                               struct IOHandlerThread *cthread;
-                               for(cthread = threads; cthread; cthread = cthread->next) {
-                                       if(cthread->main)
-                                               continue;
-                                       cthread->shutdown = 1;
-                                       pthread_join(cthread->thread, NULL);
-                               }
-                               #endif
-                               thread->shutdown = 1;
-                               IODESYNCHRONIZE(iothread_sync);
-                               break;
-                       }
-                       IODESYNCHRONIZE(iothread_sync);
-               }
-               if(!thread->run) {
-                       usleep(500000); // 500ms
-                       continue;
-               }
-               
-               // iohandler calls
-               iogc_exec();
-               iodns_poll();
-               
-       }
-       IOSYNCHRONIZE(iothread_sync);
-       if(thread == threads) {
-               threads = thread->next;
-       } else {
-               struct IOHandlerThread *cthread;
-               for(cthread = threads; cthread; cthread = cthread->next) {
-                       if(cthread->next == thread) {
-                               cthread->next = thread->next;
-                               break;
-                       }
-               }
-       }
-       iolog_trigger(IOLOG_DEBUG, "Thread %d stopped.", thread->id);
-       free(thread);
-       IODESYNCHRONIZE(iothread_sync);
-}
-
-void iohandler_run() {
-       if(!iohandler_running)
-               return;
-       iohandler_running = 1;
-       
-       struct IOHandlerThread *mainthread = calloc(1, sizeof(*mainthread));
-    if(!mainthread) {
-        iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOHandlerThread in %s:%d", __FILE__, __LINE__);
-        return;
-    }
-       threads = mainthread;
-       
-       mainthread->main = 1;
-       mainthread->run = 1;
-       mainthread->shutdown = 0;
-       
-       iohandler_worker(1);
-       
-       _stop_iodns(); /* possible worker thread */
-}
-
diff --git a/src/IOHandler.h b/src/IOHandler.h
deleted file mode 100644 (file)
index 3cba91d..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/* IOHandler.h - IOMultiplexer v2
- * Copyright (C) 2014  Philipp Kreil (pk910)
- * 
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License 
- * along with this program. If not, see <http://www.gnu.org/licenses/>. 
- */
-#ifndef _IOHandler_h
-#define _IOHandler_h
-#ifdef _IOHandler_internals
-
-#endif
-
-void iohandler_init();
-void iohandler_run();
-void iohandler_stop();
-
-void iohandler_set_threads(int threads); /* default: 1 */
-void iohandler_set_gc(int enabled); /* default: enabled */
-
-#endif
diff --git a/src/IOHandler/.gitignore b/src/IOHandler/.gitignore
new file mode 100644 (file)
index 0000000..95c9342
--- /dev/null
@@ -0,0 +1,5 @@
+.deps
+Makefile.in
+Makefile
+*.o
+*.a
diff --git a/src/IOHandler/IODNSAddress.struct.h b/src/IOHandler/IODNSAddress.struct.h
new file mode 100644 (file)
index 0000000..64f6f31
--- /dev/null
@@ -0,0 +1,27 @@
+/* IODNSAddress.struct.h - IOMultiplexer v2
+ * Copyright (C) 2014  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+#ifndef _IODNSAddress_struct_h
+#define _IODNSAddress_struct_h
+#include <sys/time.h>
+#include <stddef.h>
+
+struct IODNSAddress {
+       size_t addresslen;
+       struct sockaddr *address;
+};
+
+#endif
diff --git a/src/IOHandler/IODNSEngine_cares.c b/src/IOHandler/IODNSEngine_cares.c
new file mode 100644 (file)
index 0000000..2bbce18
--- /dev/null
@@ -0,0 +1,50 @@
+/* IODNSEngine_cares.c - IOMultiplexer
+ * Copyright (C) 2014  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+#define _IOHandler_internals
+#include "IOInternal.h"
+#include "IOHandler.h"
+#include "IODNSLookup.h"
+
+static int dnsengine_cares_init() {
+       /* TODO */
+    return 0;
+}
+
+static void dnsengine_cares_stop() {
+       /* TODO */
+}
+
+static void dnsengine_cares_add(struct _IODNSQuery *iodns) {
+    /* TODO */
+}
+
+static void dnsengine_cares_remove(struct _IODNSQuery *iodns) {
+    /* TODO */
+}
+
+static void dnsengine_cares_loop() {
+    /* TODO */
+}
+
+struct IODNSEngine dnsengine_cares = {
+    .name = "c-ares",
+    .init = dnsengine_cares_init,
+       .stop = dnsengine_cares_stop,
+    .add = dnsengine_cares_add,
+    .remove = dnsengine_cares_remove,
+    .loop = dnsengine_cares_loop,
+};
diff --git a/src/IOHandler/IODNSEngine_default.c b/src/IOHandler/IODNSEngine_default.c
new file mode 100644 (file)
index 0000000..43f6b12
--- /dev/null
@@ -0,0 +1,214 @@
+/* IODNSEngine_default.c - IOMultiplexer
+ * Copyright (C) 2014  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+#define _IOHandler_internals
+#include "IOInternal.h"
+#include "IOHandler.h"
+#include "IOLog.h"
+#include "IODNSLookup.h"
+
+#ifdef WIN32
+#define _WIN32_WINNT 0x501
+#include <windows.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#endif
+#include "compat/inet.h"
+#include <stdlib.h>
+#include <string.h>
+
+
+#ifdef IODNS_USE_THREADS
+static pthread_t iodns_thread;
+static int iodns_thread_running = 1;
+
+static pthread_cond_t iodns_cond;
+static pthread_mutex_t iodns_sync, iodns_sync2;
+#endif
+static int iodns_loop_blocking = 0;
+
+static void iodns_process_queries();
+
+#ifdef IODNS_USE_THREADS
+static void *dnsengine_worker_main(void *arg) {
+       struct _IODNSQuery *query;
+       while(iodns_thread_running) {
+               IOSYNCHRONIZE(iodns_sync);
+               for(query = iodnsquery_first; query; query = query->next) {
+                       if((query->flags & IODNSFLAG_RUNNING))
+                               break;
+               }
+               IODESYNCHRONIZE(iodns_sync);
+               if(!query)
+                       pthread_cond_wait(&iodns_cond, &iodns_sync2);
+               
+               if(iodns_thread_running)
+                       iodns_process_queries();
+       }
+       return NULL;
+}
+#endif
+
+static int dnsengine_default_init() {
+       #ifdef IODNS_USE_THREADS
+       /* create worker thread */
+       pthread_cond_init(&iodns_cond, NULL);
+       IOTHREAD_MUTEX_INIT(iodns_sync);
+       IOTHREAD_MUTEX_INIT(iodns_sync2);
+       
+       iodns_thread_running = 1;
+       
+       int thread_err;
+       thread_err = pthread_create(&iodns_thread, NULL, dnsengine_worker_main, NULL);
+       if(thread_err) {
+               iolog_trigger(IOLOG_ERROR, "could not create pthread in %s:%d (Returned: %i)", __FILE__, __LINE__, thread_err);
+               iodns_loop_blocking = 1;
+               iodns_thread_running = 0;
+       }
+       #else
+       iodns_loop_blocking = 1;
+       #endif
+    return 1;
+}
+
+static void dnsengine_default_stop() {
+       #ifdef IODNS_USE_THREADS
+       if(iodns_thread_running) {
+               iodns_thread_running = 0;
+               IOSYNCHRONIZE(iodns_sync2);
+               pthread_cond_signal(&iodns_cond);
+               IODESYNCHRONIZE(iodns_sync2);
+               pthread_join(iodns_thread, NULL);
+       }
+       #endif
+}
+
+static void dnsengine_default_add(struct _IODNSQuery *iodns) {
+    #ifdef IODNS_USE_THREADS
+       if(iodns_thread_running) {
+               IOSYNCHRONIZE(iodns_sync2);
+               pthread_cond_signal(&iodns_cond);
+               IODESYNCHRONIZE(iodns_sync2);
+       }
+       #endif
+}
+
+static void dnsengine_default_remove(struct _IODNSQuery *iodns) {
+    /* unused */
+}
+
+static void dnsengine_default_loop() {
+    if(iodns_loop_blocking)
+               iodns_process_queries();
+}
+
+static void iodns_process_queries() {
+       enum IODNSEventType querystate;
+    struct addrinfo hints, *res, *allres;
+    struct _IODNSQuery *iodns, *next_iodns;
+    struct IODNSResult *dnsresult;
+       iodns_process_queries_start:
+       IOSYNCHRONIZE(iodns_sync);
+    for(iodns = iodnsquery_first; iodns; iodns = next_iodns) {
+        next_iodns = iodns->next;
+               
+               if(!(iodns->flags & IODNSFLAG_RUNNING))
+                       continue;
+               if((iodns->flags & IODNSFLAG_PROCESSING))
+                       continue;
+               
+               IODESYNCHRONIZE(iodns_sync);
+               
+        querystate = IODNSEVENT_FAILED;
+        
+        if((iodns->type & IODNS_FORWARD)) {
+            memset (&hints, 0, sizeof (hints));
+            hints.ai_family = PF_UNSPEC;
+            hints.ai_socktype = SOCK_STREAM;
+            hints.ai_flags |= AI_CANONNAME;
+                       int ret;
+            if (!(ret = getaddrinfo(iodns->request.host, NULL, &hints, &allres))) {
+                               res = allres;
+                while (res) {
+                    switch (res->ai_family) {
+                    case AF_INET:
+                        if((iodns->type & IODNS_RECORD_A)) {
+                            dnsresult = malloc(sizeof(*dnsresult));
+                            dnsresult->type = IODNS_RECORD_A;
+                            dnsresult->result.addr.addresslen = res->ai_addrlen;
+                            dnsresult->result.addr.address = malloc(dnsresult->result.addr.addresslen);
+                            memcpy(dnsresult->result.addr.address, res->ai_addr, dnsresult->result.addr.addresslen);
+                            dnsresult->next = iodns->result;
+                            iodns->result = dnsresult;
+                            
+                            char str[INET_ADDRSTRLEN];
+                                                       inet_ntop( AF_INET, &((struct sockaddr_in *)dnsresult->result.addr.address)->sin_addr, str, INET_ADDRSTRLEN );
+                            iolog_trigger(IOLOG_DEBUG, "Resolved %s to (A): %s", iodns->request.host, str);
+                            
+                            querystate = IODNSEVENT_SUCCESS;
+                        }
+                        break;
+                    case AF_INET6:
+                        if((iodns->type & IODNS_RECORD_AAAA)) {
+                            dnsresult = malloc(sizeof(*dnsresult));
+                            dnsresult->type = IODNS_RECORD_AAAA;
+                            dnsresult->result.addr.addresslen = res->ai_addrlen;
+                            dnsresult->result.addr.address = calloc(dnsresult->result.addr.addresslen, 1);
+                            memcpy(dnsresult->result.addr.address, res->ai_addr, dnsresult->result.addr.addresslen);
+                            dnsresult->next = iodns->result;
+                            iodns->result = dnsresult;
+                            
+                            char str[INET6_ADDRSTRLEN];
+                                                       inet_ntop( AF_INET6, &((struct sockaddr_in6 *)dnsresult->result.addr.address)->sin6_addr, str, INET6_ADDRSTRLEN );
+                            iolog_trigger(IOLOG_DEBUG, "Resolved %s to (AAAA): %s", iodns->request.host, str);
+                            
+                            querystate = IODNSEVENT_SUCCESS;
+                        }
+                        break;
+                    }
+                    res = res->ai_next;
+                }
+                freeaddrinfo(allres);
+            } else {
+                               iolog_trigger(IOLOG_WARNING, "getaddrinfo returned error code: %d", ret);
+                       }
+        }
+               IOSYNCHRONIZE(iodns_sync);
+               if(!(iodns->flags & IODNSFLAG_RUNNING)) {
+                       iodns_free_result(iodns->result);
+                       _free_dnsquery(iodns);
+                       IODESYNCHRONIZE(iodns_sync);
+                       goto iodns_process_queries_start;
+               }
+               iodns->flags &= ~(IODNSFLAG_PROCESSING | IODNSFLAG_RUNNING);
+               IODESYNCHRONIZE(iodns_sync);
+               iodns_event_callback(iodns, querystate);
+               goto iodns_process_queries_start;
+    }
+}
+
+struct IODNSEngine dnsengine_default = {
+    .name = "default",
+    .init = dnsengine_default_init,
+       .stop = dnsengine_default_stop,
+    .add = dnsengine_default_add,
+    .remove = dnsengine_default_remove,
+    .loop = dnsengine_default_loop,
+};
diff --git a/src/IOHandler/IODNSLookup.c b/src/IOHandler/IODNSLookup.c
new file mode 100644 (file)
index 0000000..e39a9cf
--- /dev/null
@@ -0,0 +1,223 @@
+/* IODNSLookup.c - IOMultiplexer
+ * Copyright (C) 2014  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+#define _IOHandler_internals
+#include "IOInternal.h"
+#include "IOHandler.h"
+#include "IODNSLookup.h"
+#include "IOLog.h"
+#include "IOSockets.h"
+
+#include <string.h>
+
+struct _IODNSQuery *iodnsquery_first = NULL;
+struct _IODNSQuery *iodnsquery_last = NULL;
+
+struct IODNSEngine *dnsengine = NULL;
+
+static void iodns_init_engine() {
+       if(dnsengine)
+               return;
+       //try DNS engines
+       if(dnsengine_cares.init && dnsengine_cares.init())
+               dnsengine = &dnsengine_cares;
+       else if(dnsengine_default.init && dnsengine_default.init())
+               dnsengine = &dnsengine_default;
+       else {
+               iolog_trigger(IOLOG_FATAL, "found no useable IO DNS engine");
+               return;
+       }
+       iolog_trigger(IOLOG_DEBUG, "using %s IODNS engine", dnsengine->name);
+}
+
+void _init_iodns() {
+       iodns_init_engine();
+}
+
+struct _IODNSQuery *_create_dnsquery() {
+       struct _IODNSQuery *query = calloc(1, sizeof(*query));
+       if(!query) {
+               iolog_trigger(IOLOG_ERROR, "could not allocate memory for _IODNSQuery in %s:%d", __FILE__, __LINE__);
+               return NULL;
+       }
+       if(iodnsquery_last)
+               iodnsquery_last->next = query;
+       else
+               iodnsquery_first = query;
+       query->prev = iodnsquery_last;
+       iodnsquery_last = query;
+       return query;
+}
+
+void _start_dnsquery(struct _IODNSQuery *query) {
+       query->flags |= IODNSFLAG_RUNNING;
+       dnsengine->add(query);
+}
+
+void _free_dnsquery(struct _IODNSQuery *query) {
+       if(query->prev)
+               query->prev->next = query->next;
+       else
+               iodnsquery_first = query->next;
+       if(query->next)
+               query->next->prev = query->prev;
+       else
+               iodnsquery_last = query->prev;
+       if((query->type & IODNS_REVERSE) && query->request.addr.address)
+               free(query->request.addr.address);
+       free(query);
+}
+
+void _stop_dnsquery(struct _IODNSQuery *query) {
+       if((query->flags & IODNSFLAG_RUNNING)) {
+               query->flags &= ~IODNSFLAG_RUNNING;
+               dnsengine->remove(query);
+       }
+       if(!(query->flags & IODNSFLAG_PROCESSING))
+               _free_dnsquery(query);
+}
+
+void iodns_event_callback(struct _IODNSQuery *query, enum IODNSEventType state) {
+       if((query->flags & IODNSFLAG_PARENT_PUBLIC)) {
+               struct IODNSQuery *descriptor = query->parent;
+               struct IODNSEvent event;
+               event.type = state;
+               event.query = descriptor;
+               event.result = query->result;
+               
+               descriptor->query = NULL;
+               _stop_dnsquery(query);
+               
+               if(descriptor->callback)
+                       descriptor->callback(&event);
+               
+               iogc_add(descriptor);
+       } else if((query->flags & IODNSFLAG_PARENT_SOCKET)) {
+               struct IODNSEvent event;
+               event.type = state;
+               event.query = NULL;
+               event.result = query->result;
+               void *parent = query->parent;
+               
+               _stop_dnsquery(query);
+               iosocket_lookup_callback(parent, &event);
+               
+       }
+}
+
+void iodns_poll() {
+       if(dnsengine)
+               dnsengine->loop();
+}
+
+/* public functions */
+
+struct IODNSQuery *iodns_getaddrinfo(char *hostname, int records, iodns_callback *callback) {
+       if(!(records & IODNS_FORWARD) || !hostname || !callback)
+               return NULL;
+       
+       struct IODNSQuery *descriptor = calloc(1, sizeof(*descriptor));
+       if(!descriptor) {
+               iolog_trigger(IOLOG_ERROR, "could not allocate memory for IODNSQuery in %s:%d", __FILE__, __LINE__);
+               return NULL;
+       }
+       
+       struct _IODNSQuery *query = _create_dnsquery();
+       if(!query) {
+               free(descriptor);
+               return NULL;
+       }
+       
+       query->parent = descriptor;
+       query->flags |= IODNSFLAG_PARENT_PUBLIC;
+       descriptor->query = query;
+       
+       query->request.host = strdup(hostname);
+       query->type = (records & IODNS_FORWARD);
+       
+       descriptor->callback = callback;
+       
+       _start_dnsquery(query);
+       return descriptor;
+}
+
+struct IODNSQuery *iodns_getnameinfo(const struct sockaddr *addr, size_t addrlen, iodns_callback *callback) {
+       if(!addr || !callback)
+               return NULL;
+       
+       struct IODNSQuery *descriptor = calloc(1, sizeof(*descriptor));
+       if(!descriptor) {
+               iolog_trigger(IOLOG_ERROR, "could not allocate memory for IODNSQuery in %s:%d", __FILE__, __LINE__);
+               return NULL;
+       }
+       
+       struct _IODNSQuery *query = _create_dnsquery();
+       if(!query) {
+               free(descriptor);
+               return NULL;
+       }
+       
+       query->parent = descriptor;
+       query->flags |= IODNSFLAG_PARENT_PUBLIC;
+       descriptor->query = query;
+       
+       query->type = IODNS_RECORD_PTR;
+       query->request.addr.addresslen = addrlen;
+       query->request.addr.address = malloc(addrlen);
+       if(!query->request.addr.address) {
+               iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__);
+               _free_dnsquery(query);
+               free(descriptor);
+               return NULL;
+       }
+       memcpy(query->request.addr.address, addr, addrlen);
+       
+       descriptor->callback = callback;
+       
+       _start_dnsquery(query);
+       return descriptor;
+}
+
+void iodns_abort(struct IODNSQuery *descriptor) {
+       if(!descriptor)
+               return;
+       
+       struct _IODNSQuery *query = descriptor->query;
+       if(!query) {
+               iolog_trigger(IOLOG_WARNING, "called iodns_abort for destroyed IODNSQuery in %s:%d", __FILE__, __LINE__);
+               return;
+       }
+       
+       _stop_dnsquery(query);
+}
+
+void iodns_free_result(struct IODNSResult *result) {
+       struct IODNSResult *next;
+       for(;result;result = next) {
+               next = result->next;
+               
+               if((result->type & IODNS_FORWARD)) {
+                       if(result->result.addr.address)
+                               free(result->result.addr.address);
+               }
+               if((result->type & IODNS_REVERSE)) {
+                       if(result->result.host)
+                               free(result->result.host);
+               }
+               free(result);
+       }
+}
+
diff --git a/src/IOHandler/IODNSLookup.h b/src/IOHandler/IODNSLookup.h
new file mode 100644 (file)
index 0000000..29574cb
--- /dev/null
@@ -0,0 +1,155 @@
+/* IODNSLookup.h - IOMultiplexer v2
+ * Copyright (C) 2014  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+#ifndef _IODNSLookup_h
+#define _IODNSLookup_h
+#include <stdlib.h>
+#include "IODNSAddress.struct.h"
+
+#ifndef _IOHandler_internals
+#include "IOHandler.h"
+#else
+
+struct IODNSEngine;
+extern struct IODNSEngine dnsengine_cares;
+extern struct IODNSEngine dnsengine_default;
+
+struct _IODNSQuery;
+extern struct _IODNSQuery *iodnsquery_first;
+extern struct _IODNSQuery *iodnsquery_last;
+
+/* Multithreading */
+#ifdef IODNS_USE_THREADS
+#ifndef HAVE_PTHREAD_H
+#undef IODNS_USE_THREADS
+#endif
+#endif
+#ifdef IODNS_USE_THREADS
+#include <pthread.h>
+#ifdef PTHREAD_MUTEX_RECURSIVE_NP
+#define PTHREAD_MUTEX_RECURSIVE_VAL PTHREAD_MUTEX_RECURSIVE_NP
+#else
+#define PTHREAD_MUTEX_RECURSIVE_VAL PTHREAD_MUTEX_RECURSIVE
+#endif
+#define IOTHREAD_MUTEX_INIT(var) { \
+    pthread_mutexattr_t mutex_attr; \
+    pthread_mutexattr_init(&mutex_attr);\
+    pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE_VAL);\
+    pthread_mutex_init(&var, &mutex_attr); \
+}
+#define IOSYNCHRONIZE(var) pthread_mutex_lock(&var)
+#define IODESYNCHRONIZE(var) pthread_mutex_unlock(&var)
+#else
+#define IOTHREAD_MUTEX_INIT(var)
+#define IOSYNCHRONIZE(var)
+#define IODESYNCHRONIZE(var)
+#endif
+
+#define IODNSFLAG_RUNNING        0x01
+#define IODNSFLAG_PROCESSING     0x02
+#define IODNSFLAG_PARENT_PUBLIC  0x04
+#define IODNSFLAG_PARENT_SOCKET  0x08
+
+struct IODNSResult;
+
+struct _IODNSQuery {
+       void *query;
+       
+       unsigned int flags : 8;
+       unsigned int type : 8;
+    union {
+               struct IODNSAddress addr;
+               char *host;
+       } request;
+       
+       struct IODNSResult *result;
+       
+       void *parent;
+       
+       struct _IODNSQuery *next, *prev;
+};
+
+struct IODNSEngine {
+    const char *name;
+    int (*init)();
+       void (*stop)();
+    void (*add)(struct _IODNSQuery *query);
+    void (*remove)(struct _IODNSQuery *query);
+    void (*loop)();
+};
+
+void _init_iodns();
+void _stop_iodns();
+struct _IODNSQuery *_create_dnsquery();
+void _start_dnsquery(struct _IODNSQuery *query);
+void _stop_dnsquery(struct _IODNSQuery *query);
+
+/* call only from engines! */
+enum IODNSEventType;
+void _free_dnsquery(struct _IODNSQuery *query);
+void iodns_event_callback(struct _IODNSQuery *query, enum IODNSEventType state);
+
+void iodns_poll();
+
+#endif
+
+struct IODNSEvent;
+struct sockaddr;
+
+#define IODNS_CALLBACK(NAME) void NAME(struct IODNSEvent *event)
+typedef IODNS_CALLBACK(iodns_callback);
+
+enum IODNSEventType {
+    IODNSEVENT_SUCCESS,
+    IODNSEVENT_FAILED
+};
+
+#define IODNS_RECORD_A    0x01
+#define IODNS_RECORD_AAAA 0x02
+#define IODNS_RECORD_PTR  0x04
+
+#define IODNS_FORWARD     0x03
+#define IODNS_REVERSE     0x04
+
+struct IODNSQuery {
+       void *query;
+       
+    iodns_callback *callback;
+    void *data;
+};
+
+struct IODNSResult {
+    unsigned int type : 8;
+    union {
+               struct IODNSAddress addr;
+               char *host;
+       } result;
+    struct IODNSResult *next;
+};
+
+struct IODNSEvent {
+    enum IODNSEventType type;
+    struct IODNSQuery *query;
+       struct IODNSResult *result;
+};
+
+struct IODNSQuery *iodns_getaddrinfo(char *hostname, int records, iodns_callback *callback);
+struct IODNSQuery *iodns_getnameinfo(const struct sockaddr *addr, size_t addrlen, iodns_callback *callback);
+void iodns_abort(struct IODNSQuery *query);
+
+void iodns_free_result(struct IODNSResult *result);
+
+#endif
diff --git a/src/IOHandler/IOEngine_epoll.c b/src/IOHandler/IOEngine_epoll.c
new file mode 100644 (file)
index 0000000..060f87f
--- /dev/null
@@ -0,0 +1,141 @@
+/* IOEngine_epoll.c - IOMultiplexer
+ * Copyright (C) 2014  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+#define _IOHandler_internals
+#include "IOInternal.h"
+#include "IOHandler.h"
+#include "IOLog.h"
+#include "IOSockets.h"
+#include "IOTimer.h"
+
+#ifdef HAVE_SYS_EPOLL_H
+#include <sys/epoll.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#define MAX_EVENTS 32
+
+static int epoll_fd;
+
+static int engine_epoll_init() {
+       epoll_fd = epoll_create(IOHANDLER_MAX_SOCKETS);
+       if (epoll_fd < 0)
+               return 0;
+       return 1;
+}
+
+static void engine_epoll_add(struct _IOSocket *iosock) {
+       //add Socket FD to the epoll queue
+       struct epoll_event evt;
+       int res;
+
+       evt.events = EPOLLHUP | EPOLLIN | (iosocket_wants_writes(iosock) ? EPOLLOUT : 0);
+       evt.data.ptr = iosock;
+       res = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, iosock->fd, &evt);
+       if(res < 0)
+               iolog_trigger(IOLOG_ERROR, "could not add _IOSocket %d to epoll queue. (returned: %d)", iosock->fd, res);
+}
+
+static void engine_epoll_remove(struct _IOSocket *iosock) {
+       struct epoll_event evt;
+       epoll_ctl(epoll_fd, EPOLL_CTL_DEL, iosock->fd, &evt);
+}
+
+static void engine_epoll_update(struct _IOSocket *iosock) {
+       struct epoll_event evt;
+       int res;
+
+       evt.events = EPOLLHUP | EPOLLIN | (iosocket_wants_writes(iosock) ? EPOLLOUT : 0);
+       evt.data.ptr = iosock;
+       res = epoll_ctl(epoll_fd, EPOLL_CTL_MOD, iosock->fd, &evt);
+       if(res < 0)
+               iolog_trigger(IOLOG_ERROR, "could not update _IOSocket %d in epoll queue. (returned: %d)", iosock->fd, res);
+}
+
+static void engine_epoll_loop(struct timeval *timeout) {
+       struct epoll_event evts[MAX_EVENTS];
+       int msec, msec2;
+       int events;
+       int epoll_result;
+       struct timeval now;
+       
+       //check timers
+       gettimeofday(&now, NULL);
+       if(iotimer_sorted_descriptors && timeval_is_bigger(now, iotimer_sorted_descriptors->timeout))
+               _trigger_timer();
+       
+       //get timeout (timer or given timeout)
+       if(iotimer_sorted_descriptors) {
+               msec = (iotimer_sorted_descriptors->timeout.tv_sec - now.tv_sec) * 1000;
+               msec += (iotimer_sorted_descriptors->timeout.tv_usec - now.tv_usec) / 1000;
+       }
+       if(timeout) {
+               msec2 = (timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
+               if(!iotimer_sorted_descriptors || msec2 < msec)
+                       msec = msec2;
+       } else if(!iotimer_sorted_descriptors)
+               msec = -1;
+       
+       //epoll system call
+       epoll_result = epoll_wait(epoll_fd, evts, MAX_EVENTS, msec);
+       
+       if (epoll_result < 0) {
+               if (errno != EINTR) {
+                       iolog_trigger(IOLOG_FATAL, "epoll_wait() failed with errno %d: %s", errno, strerror(errno));
+                       return;
+               }
+       } else {
+               int i;
+               for(i = 0; i < epoll_result; i++) {
+                       events = evts[i].events;
+                       iosocket_events_callback(evts[i].data.ptr, (events & (EPOLLIN | EPOLLHUP)), (events & EPOLLOUT));
+               }
+       }
+       
+       //check timers
+       gettimeofday(&now, NULL);
+       if(iotimer_sorted_descriptors && timeval_is_bigger(now, iotimer_sorted_descriptors->timeout))
+               _trigger_timer();
+}
+
+static void engine_epoll_cleanup() {
+       close(epoll_fd);
+}
+
+struct IOEngine engine_epoll = {
+       .name = "epoll",
+       .init = engine_epoll_init,
+       .add = engine_epoll_add,
+       .remove = engine_epoll_remove,
+       .update = engine_epoll_update,
+       .loop = engine_epoll_loop,
+       .cleanup = engine_epoll_cleanup,
+};
+
+#else
+
+struct IOEngine engine_epoll = {
+       .name = "epoll",
+       .init = NULL,
+       .add = NULL,
+       .remove = NULL,
+       .update = NULL,
+       .loop = NULL,
+       .cleanup = NULL,
+};
+
+#endif
diff --git a/src/IOHandler/IOEngine_kevent.c b/src/IOHandler/IOEngine_kevent.c
new file mode 100644 (file)
index 0000000..1c39cc6
--- /dev/null
@@ -0,0 +1,153 @@
+/* IOengine_kevent.c - IOMultiplexer
+ * Copyright (C) 2014  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+#define _IOHandler_internals
+#include "IOInternal.h"
+#include "IOHandler.h"
+#include "IOLog.h"
+#include "IOSockets.h"
+
+#ifdef HAVE_SYS_EVENT_H
+#include <sys/event.h>
+#include <errno.h>
+
+#define MAX_EVENTS 32
+
+static int kevent_fd;
+
+static int engine_kevent_init() {
+       kevent_fd = kqueue();
+       if (kevent_fd < 0)
+               return 0;
+       return 1;
+}
+
+static void engine_kevent_add(struct _IOSocket *iosock) {
+       //add Socket FD to the kevent queue
+       struct kevent changes[2];
+       int nchanges = 0;
+       int res;
+
+       EV_SET(&changes[nchanges++], iosock->fd, EVFILT_READ, EV_ADD, 0, 0, iosock);
+       if (iosocket_wants_writes(iosock))
+               EV_SET(&changes[nchanges++], iosock->fd, EVFILT_WRITE, EV_ADD, 0, 0, iosock);
+       
+       res = kevent(kevent_fd, changes, nchanges, NULL, 0, NULL);
+       if(res < 0)
+               iolog_trigger(IOLOG_ERROR, "could not add _IOSocket %d to kevent queue. (returned: %d)", iosock->fd, res);
+}
+
+static void engine_kevent_remove(struct _IOSocket *iosock) {
+       struct kevent changes[2];
+       int nchanges = 0;
+
+       EV_SET(&changes[nchanges++], iosock->fd, EVFILT_READ, EV_DELETE, 0, 0, iosock);
+       EV_SET(&changes[nchanges++], iosock->fd, EVFILT_WRITE, EV_DELETE, 0, 0, iosock);
+       kevent(kevent_fd, changes, nchanges, NULL, 0, NULL);
+}
+
+static void engine_kevent_update(struct _IOSocket *iosock) {
+       struct kevent changes[2];
+       int nchanges = 0;
+       int res;
+
+       EV_SET(&changes[nchanges++], iosock->fd, EVFILT_READ, EV_ADD, 0, 0, iosock);
+       EV_SET(&changes[nchanges++], iosock->fd, EVFILT_WRITE, iosocket_wants_writes(iosock) ? EV_ADD : EV_DELETE, 0, 0, iosock);
+       
+       res = kevent(kevent_fd, changes, nchanges, NULL, 0, NULL);
+       if(res < 0)
+               iolog_trigger(IOLOG_ERROR, "could not update _IOSocket %d in kevent queue. (returned: %d)", iosock->fd, res);
+}
+
+static void engine_kevent_loop(struct timeval *timeout) {
+       struct kevent events[MAX_EVENTS];
+       struct timespec ts;
+       int msec;
+       int kevent_result;
+       struct timeval now, tout;
+       
+       //check timers
+       gettimeofday(&now, NULL);
+       if(iotimer_sorted_descriptors && timeval_is_bigger(now, iotimer_sorted_descriptors->timeout))
+               _trigger_timer();
+       
+       //get timeout (timer or given timeout)
+       if(iotimer_sorted_descriptors) {
+               tout = iotimer_sorted_descriptors->timeout;
+               tout.tv_sec -= now.tv_sec;
+               tout.tv_usec -= now.tv_usec;
+               if(tout.tv_usec < 0) {
+                       tout.tv_sec --;
+                       tout.tv_usec += 1000000;
+               }
+       }
+       if(timeout) {
+               if(!iotimer_sorted_descriptors || timeval_is_smaler((*timeout), tout)) {
+                       tout.tv_usec = timeout->tv_usec;
+                       tout.tv_sec = timeout->tv_sec;
+               }
+               timeout = &tout;
+       } else if(iotimer_sorted_descriptors)
+               timeout = &tout;
+       
+       
+       //select system call
+       kevent_result = kevent(kevent_fd, NULL, 0, events, MAX_EVENTS, timeout);
+       
+       if (kevent_result < 0) {
+               if (errno != EINTR) {
+                       iolog_trigger(IOLOG_FATAL, "kevent() failed with errno %d: %s", errno, strerror(errno));
+                       return;
+               }
+       } else {
+               int i;
+               for(i = 0; i < kevent_result; i++)
+                       iosocket_events_callback(events[i].udata, (events[i].filter == EVFILT_READ), (events[i].filter == EVFILT_WRITE));
+       }
+       
+       //check timers
+       gettimeofday(&now, NULL);
+       if(iotimer_sorted_descriptors && timeval_is_bigger(now, iotimer_sorted_descriptors->timeout))
+               _trigger_timer();
+}
+
+static void engine_kevent_cleanup() {
+       close(kevent_fd);
+}
+
+struct IOEngine engine_kevent = {
+       .name = "kevent",
+       .init = engine_kevent_init,
+       .add = engine_kevent_add,
+       .remove = engine_kevent_remove,
+       .update = engine_kevent_update,
+       .loop = engine_kevent_loop,
+       .cleanup = engine_kevent_cleanup,
+};
+
+#else
+
+struct IOEngine engine_kevent = {
+       .name = "kevent",
+       .init = NULL,
+       .add = NULL,
+       .remove = NULL,
+       .update = NULL,
+       .loop = NULL,
+       .cleanup = NULL,
+};
+
+#endif
diff --git a/src/IOHandler/IOEngine_select.c b/src/IOHandler/IOEngine_select.c
new file mode 100644 (file)
index 0000000..c0405f4
--- /dev/null
@@ -0,0 +1,146 @@
+/* IOEngine_select.c - IOMultiplexer
+ * Copyright (C) 2014  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+#define _IOHandler_internals
+#include "IOInternal.h"
+#include "IOHandler.h"
+#include "IOLog.h"
+#include "IOSockets.h"
+#include "IOTimer.h"
+
+#include <errno.h>
+#include <time.h>
+#ifdef WIN32
+#define _WIN32_WINNT 0x501
+#include <windows.h>
+#include <winsock2.h>
+#else
+#include <string.h>
+#include <stdio.h>
+#endif
+
+/* compat */
+#include "compat/utime.h"
+
+static int engine_select_init() {
+       return 1;
+}
+
+static void engine_select_add(struct _IOSocket *iosock) {
+       /* empty */
+}
+
+static void engine_select_remove(struct _IOSocket *iosock) {
+       /* empty */
+}
+
+static void engine_select_update(struct _IOSocket *iosock) {
+       /* empty */
+}
+
+static void engine_select_loop(struct timeval *timeout) {
+       fd_set read_fds;
+       fd_set write_fds;
+       unsigned int fds_size = 0;
+       struct _IOSocket *iosock, *next_iosock;
+       struct timeval now, tout;
+       int select_result;
+       
+       //clear fds
+       FD_ZERO(&read_fds);
+       FD_ZERO(&write_fds);
+       
+       //check timers
+       gettimeofday(&now, NULL);
+       if(iotimer_sorted_descriptors && timeval_is_bigger(now, iotimer_sorted_descriptors->timeout))
+               _trigger_timer();
+       
+       //get timeout (timer or given timeout)
+       if(iotimer_sorted_descriptors) {
+               tout = iotimer_sorted_descriptors->timeout;
+               tout.tv_sec -= now.tv_sec;
+               tout.tv_usec -= now.tv_usec;
+               if(tout.tv_usec < 0) {
+                       tout.tv_sec --;
+                       tout.tv_usec += 1000000;
+               }
+       }
+       if(timeout) {
+               if(!iotimer_sorted_descriptors || timeval_is_smaler((*timeout), tout)) {
+                       tout.tv_usec = timeout->tv_usec;
+                       tout.tv_sec = timeout->tv_sec;
+               }
+               timeout = &tout;
+       } else if(iotimer_sorted_descriptors)
+               timeout = &tout;
+       
+       select_result = 0;
+       for(iosock = iosocket_first; iosock; iosock = iosock->next) {
+               if(!(iosock->socket_flags & IOSOCKETFLAG_ACTIVE)) 
+                       continue;
+               if(iosock->fd > fds_size)
+                       fds_size = iosock->fd;
+               FD_SET(iosock->fd, &read_fds);
+               select_result++;
+               if(iosocket_wants_writes(iosock))
+                       FD_SET(iosock->fd, &write_fds);
+       }
+
+       if(select_result) //select system call
+               select_result = select(fds_size + 1, &read_fds, &write_fds, NULL, timeout);
+       else if(timeout) {
+               usleep_tv(*timeout);
+               select_result = 0;
+       } else
+               usleep(10000); // 10ms
+       
+       if (select_result < 0) {
+               if (errno != EINTR) {
+                       iolog_trigger(IOLOG_FATAL, "select() failed with errno %d %d: %s", select_result, errno, strerror(errno));
+                       return;
+               }
+       }
+       
+       gettimeofday(&now, NULL);
+       
+       //check all descriptors
+       for(iosock = iosocket_first; iosock; iosock = next_iosock) {
+               next_iosock = iosock->next;
+               if(!(iosock->socket_flags & IOSOCKETFLAG_ACTIVE))
+                       return;
+               if(FD_ISSET(iosock->fd, &read_fds) || FD_ISSET(iosock->fd, &write_fds))
+                       iosocket_events_callback(iosock, FD_ISSET(iosock->fd, &read_fds), FD_ISSET(iosock->fd, &write_fds));
+       }
+       
+       //check timers
+       if(iotimer_sorted_descriptors && timeval_is_bigger(now, iotimer_sorted_descriptors->timeout))
+               _trigger_timer();
+       
+}
+
+static void engine_select_cleanup() {
+       /* empty */
+}
+
+struct IOEngine engine_select = {
+       .name = "select",
+       .init = engine_select_init,
+       .add = engine_select_add,
+       .remove = engine_select_remove,
+       .update = engine_select_update,
+       .loop = engine_select_loop,
+       .cleanup = engine_select_cleanup,
+};
diff --git a/src/IOHandler/IOEngine_win32.c b/src/IOHandler/IOEngine_win32.c
new file mode 100644 (file)
index 0000000..6f755c2
--- /dev/null
@@ -0,0 +1,205 @@
+/* IOEngine_win32.c - IOMultiplexer
+ * Copyright (C) 2014  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+#define _IOHandler_internals
+#include "IOInternal.h"
+#include "IOHandler.h"
+#include "IOLog.h"
+#include "IOSockets.h"
+#include "IOTimer.h"
+
+#ifdef WIN32
+
+#define _WIN32_WINNT 0x501
+#include <windows.h>
+#include <winsock2.h>
+
+/* This is massively kludgy.  Unfortunately, the only performant I/O
+ * multiplexer with halfway decent semantics under Windows is
+ * WSAAsyncSelect() -- which requires a window that can receive
+ * messages.
+ *
+ * So ioset_win32_init() creates a hidden window and sets it up for
+ * asynchronous socket notifications.
+ */
+
+#define IDT_TIMER1 1000
+#define IDT_TIMER2 1001
+#define IDT_SOCKET 1002
+
+static HWND ioset_window;
+
+static struct _IOSocket *engine_win32_get_iosock(int fd) {
+       struct _IOSocket *iosock;
+       for(iosock = iosocket_first; iosock; iosock = iosock->next) {
+               if(iosock->fd == fd)
+                       return iosock;
+       }
+       return NULL;
+}
+
+static LRESULT CALLBACK engine_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
+       struct _IOSocket *iosock;
+       int events;
+
+       if (hWnd == ioset_window) {
+               switch (uMsg) {
+               case IDT_TIMER1:
+                       return 0;
+               case IDT_TIMER2:
+                       //check timers
+                       _trigger_timer();
+                       return 0;
+               case IDT_SOCKET:
+                       iosock = engine_win32_get_iosock(wParam);
+                       events = WSAGETSELECTEVENT(lParam);
+                       
+                       iosocket_events_callback(iosock, (events & (FD_READ | FD_ACCEPT | FD_CLOSE)) != 0, (events & (FD_WRITE | FD_CONNECT)) != 0);
+                       return 0;
+               case WM_QUIT:
+                       return 0;
+               }
+       }
+       return DefWindowProc(hWnd, uMsg, wParam, lParam);
+}
+
+static int engine_win32_init() {
+       WNDCLASSEX wcx;
+       HINSTANCE hinst;
+       WSADATA wsadata;
+       
+       // Start Windows Sockets.
+       if (WSAStartup(MAKEWORD(2, 0), &wsadata)) {
+               iolog_trigger(IOLOG_FATAL, "Unable to start Windows Sockets");
+               return 0;
+       }
+       
+       // Get Windows HINSTANCE.
+       hinst = GetModuleHandle(NULL);
+
+       // Describe and register a window class.
+       memset(&wcx, 0, sizeof(wcx));
+       wcx.cbSize = sizeof(wcx);
+       wcx.lpfnWndProc = engine_win32_wndproc;
+       wcx.hInstance = hinst;
+       wcx.lpszClassName = "IOMultiplexerMainWindow";
+       if (!RegisterClassEx(&wcx))
+               return 0;
+
+       ioset_window = CreateWindow("IOMultiplexerMainWindow", "IOMultiplexer", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hinst, NULL);
+       if (!ioset_window)
+               return 0;
+       return 1;
+}
+
+static long engine_win32_events(struct _IOSocket *iosock) {
+       if(iosock->socket_flags & IOSOCKETFLAG_LISTENING)
+               return FD_ACCEPT;
+       if(iosock->socket_flags & IOSOCKETFLAG_CONNECTING)
+               return FD_CONNECT;
+       
+       return FD_READ | FD_CLOSE | (iosocket_wants_writes(iosock) ? FD_WRITE : 0);
+}
+
+static void engine_win32_update(struct _IOSocket *iosock) {
+       long events;
+       events = engine_win32_events(iosock);
+       WSAAsyncSelect(iosock->fd, ioset_window, IDT_SOCKET, events);
+}
+
+static void engine_win32_add(struct _IOSocket *iosock) {
+       engine_win32_update(iosock);
+}
+
+static void engine_win32_remove(struct _IOSocket *iosock) {
+       unsigned long ulong = 0;
+       WSAAsyncSelect(iosock->fd, ioset_window, IDT_SOCKET, 0);
+       ioctlsocket(iosock->fd, FIONBIO, &ulong);
+}
+
+static void engine_win32_loop(struct timeval *timeout) {
+       MSG msg;
+       BOOL res;
+       int msec, msec2;
+       struct timeval now;
+       
+       //check timers
+       gettimeofday(&now, NULL);
+       if(iotimer_sorted_descriptors && timeval_is_bigger(now, iotimer_sorted_descriptors->timeout))
+               _trigger_timer();
+       
+       //get timeout (timer or given timeout)
+       if(iotimer_sorted_descriptors) {
+               msec = (iotimer_sorted_descriptors->timeout.tv_sec - now.tv_sec) * 1000;
+               msec += (iotimer_sorted_descriptors->timeout.tv_usec - now.tv_usec) / 1000;
+       }
+       if(timeout) {
+               msec2 = (timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
+               if(!iotimer_sorted_descriptors || msec2 < msec)
+                       msec = msec2;
+       } else if(!iotimer_sorted_descriptors)
+               msec = -1;
+       
+       //set TIMER
+       SetTimer(ioset_window, IDT_TIMER1, 1000, NULL);
+       if(msec > -1)
+               SetTimer(ioset_window, IDT_TIMER2, msec, NULL);
+       
+       //GetMessage system call
+       res = GetMessage(&msg, NULL, 0, 0);
+       
+       //kill TIMER
+       KillTimer(ioset_window, IDT_TIMER1);
+       if(msec > -1)
+               KillTimer(ioset_window, IDT_TIMER2);
+       
+       if (res <=0)
+               return;
+       else {
+               TranslateMessage(&msg);
+               DispatchMessage(&msg);
+       }
+}
+
+static void engine_win32_cleanup() {
+       DestroyWindow(ioset_window);
+       ioset_window = NULL;
+       WSACleanup();
+}
+
+struct IOEngine engine_win32 = {
+       .name = "win32",
+       .init = engine_win32_init,
+       .add = engine_win32_add,
+       .remove = engine_win32_remove,
+       .update = engine_win32_update,
+       .loop = engine_win32_loop,
+       .cleanup = engine_win32_cleanup,
+};
+
+#else
+
+struct IOEngine engine_win32 = {
+       .name = "win32",
+       .init = NULL,
+       .add = NULL,
+       .remove = NULL,
+       .update = NULL,
+       .loop = NULL,
+       .cleanup = NULL,
+};
+
+#endif
diff --git a/src/IOHandler/IOGarbageCollector.c b/src/IOHandler/IOGarbageCollector.c
new file mode 100644 (file)
index 0000000..d624396
--- /dev/null
@@ -0,0 +1,102 @@
+/* IOGarbageCollector.c - IOMultiplexer v2
+ * Copyright (C) 2014  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+#define _IOHandler_internals
+#include "IOInternal.h"
+#include "IOHandler.h"
+#include "IOGarbageCollector.h"
+#include "IOLog.h"
+
+#include <sys/time.h>
+#include <stdlib.h>
+
+struct IOGCObject {
+       void *object;
+       iogc_free *free_callback;
+       struct timeval timeout;
+       
+       struct IOGCObject *next;
+};
+
+static int iogc_enabled = 1;
+static struct timeval iogc_timeout;
+static struct IOGCObject *first_object = NULL, *last_object = NULL;
+
+void iogc_init() {
+       iogc_timeout.tv_usec = 0;
+       iogc_timeout.tv_sec = 10;
+}
+
+
+void iohandler_set_gc(int enabled) {
+       if(enabled)
+               iogc_enabled = 1;
+       else
+               iogc_enabled = 0;
+}
+
+void iogc_add(void *object) {
+       iogc_add_callback(object, NULL);
+}
+
+void iogc_add_callback(void *object, iogc_free *free_callback) {
+       if(!iogc_enabled) {
+               if(free_callback)
+                       free_callback(object);
+               else
+                       free(object);
+               return;
+       }
+       struct IOGCObject *obj = malloc(sizeof(*obj));
+    if(!obj) {
+        iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOGCObject in %s:%d", __FILE__, __LINE__);
+               if(free_callback)
+                       free_callback(object);
+               else
+                       free(object);
+        return;
+    }
+       obj->object = object;
+       obj->free_callback = free_callback;
+       gettimeofday(&obj->timeout, NULL);
+       obj->timeout.tv_sec += IOGC_TIMEOUT;
+       
+       obj->next = NULL;
+       if(last_object)
+               last_object->next = obj;
+       else
+               first_object = obj;
+       last_object = obj;
+}
+
+void iogc_exec() {
+       struct timeval now;
+       gettimeofday(&now, NULL);
+       
+       struct IOGCObject *obj, *next_obj;
+       for(obj = first_object; obj; obj = next_obj) {
+               if(timeval_is_smaler(obj->timeout, now)) {
+                       next_obj = obj->next;
+                       if(obj->free_callback)
+                               obj->free_callback(obj->object);
+                       else
+                               free(obj->object);
+                       free(obj);
+               } else
+                       break;
+       }
+       first_object = obj;
+}
diff --git a/src/IOHandler/IOGarbageCollector.h b/src/IOHandler/IOGarbageCollector.h
new file mode 100644 (file)
index 0000000..d1e848b
--- /dev/null
@@ -0,0 +1,27 @@
+/* IOGarbageCollector.h - IOMultiplexer v2
+ * Copyright (C) 2014  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+#ifndef _IOGarbageCollector_h
+#define _IOGarbageCollector_h
+#ifndef _IOHandler_internals
+#include "IOHandler.h"
+#else
+
+void iogc_init();
+void iogc_exec();
+
+#endif
+#endif
diff --git a/src/IOHandler/IOHandler.c b/src/IOHandler/IOHandler.c
new file mode 100644 (file)
index 0000000..ef7d654
--- /dev/null
@@ -0,0 +1,69 @@
+/* IOHandler.c - IOMultiplexer v2
+ * Copyright (C) 2014  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+#define _IOHandler_internals
+#include "IOInternal.h"
+#include "IOHandler.h"
+
+#include "IOLog.h"
+#include "IOGarbageCollector.h"
+#include "IOTimer.h"
+#include "IODNSLookup.h"
+#include "IOSockets.h"
+
+/* compat */
+#include "compat/utime.h"
+
+#define IOHANDLER_STATE_INITIALIZED  0x0001
+#define IOHANDLER_STATE_RUNNING      0x0002
+
+static int iohandler_state = 0;
+
+
+void iohandler_init() {
+       if((iohandler_state & IOHANDLER_STATE_INITIALIZED)) 
+               return;
+       
+       iolog_init();
+       iogc_init();
+       
+       _init_timers();
+       _init_iodns();
+       _init_sockets();
+       
+       iohandler_state |= IOHANDLER_STATE_INITIALIZED;
+}
+
+void iohandler_stop() {
+       iohandler_state &= ~IOHANDLER_STATE_RUNNING;
+}
+
+static void iohandler_loop() {
+       while(iohandler_state & IOHANDLER_STATE_RUNNING) { // endless loop
+               // iohandler calls
+               iogc_exec();
+               iodns_poll();
+               iosocket_loop(IOHANDLER_LOOP_MAXTIME);
+               
+       }
+}
+
+void iohandler_run() {
+       iohandler_state |= IOHANDLER_STATE_RUNNING;
+       
+       iohandler_loop();
+}
+
diff --git a/src/IOHandler/IOHandler.h b/src/IOHandler/IOHandler.h
new file mode 100644 (file)
index 0000000..1424eb5
--- /dev/null
@@ -0,0 +1,30 @@
+/* IOHandler.h - IOMultiplexer v2
+ * Copyright (C) 2014  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+#ifndef _IOHandler_h
+#define _IOHandler_h
+#include "IOHandler_config.h"
+#ifdef _IOHandler_internals
+
+#endif
+
+void iohandler_init();
+void iohandler_run();
+void iohandler_stop();
+
+void iohandler_set_gc(int enabled); /* default: enabled */
+
+#endif
diff --git a/src/IOHandler/IOHandler_config.h b/src/IOHandler/IOHandler_config.h
new file mode 100644 (file)
index 0000000..bffedc9
--- /dev/null
@@ -0,0 +1,50 @@
+/* IOHanlder_config.h - IOMultiplexer
+ * Copyright (C) 2014  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+
+/* required configure script checks
+ AC_FUNC_MALLOC
+ AC_FUNC_CALLOC
+ AC_CHECK_FUNCS([usleep select socket inet_pton inet_ntop])
+ AC_CHECK_HEADERS([fcntl.h sys/socket.h sys/select.h sys/time.h sys/types.h unistd.h windows.h winsock2.h errno.h sys/epoll.h sys/event.h])
+ AC_CHECK_LIB(ws2_32, main, [ LIBS="$LIBS -lws2_32" ], [])
+ AC_CHECK_LIB(ssl, SSL_read, [
+   AC_CHECK_LIB(crypto, X509_new, [
+     AC_CHECK_HEADERS(openssl/ssl.h openssl/err.h openssl/rand.h, [
+       LIBS="$LIBS -lssl -lcrypto"
+     ])
+   ])
+ ])
+ AC_CHECK_LIB(pthread, pthread_create, [
+   AC_CHECK_HEADERS(pthread.h, [
+     LIBS="$LIBS -lpthread"
+   ])
+ ])
+*/
+// configure config file
+#include "../../config.h"
+
+#define IOHANDLER_MAX_SOCKETS 1024
+#define IOHANDLER_LOOP_MAXTIME 100000 /* 100ms */
+
+#define IOSOCKET_PARSE_DELIMITERS_COUNT 5
+#define IOSOCKET_PARSE_LINE_LIMIT 1024
+#define IOSOCKET_PRINTF_LINE_LEN  1024
+
+//#define IODNS_USE_THREADS
+
+#define IOGC_TIMEOUT 60
diff --git a/src/IOHandler/IOInternal.h b/src/IOHandler/IOInternal.h
new file mode 100644 (file)
index 0000000..e5dc207
--- /dev/null
@@ -0,0 +1,32 @@
+/* IOInternal.h - IOMultiplexer v2
+ * Copyright (C) 2014  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+#ifndef _IOInternal_h
+#define _IOInternal_h
+#ifndef _IOHandler_internals
+#include "IOHandler.h"
+#else
+
+#define timeval_is_bigger(x,y) ((x.tv_sec > y.tv_sec) || (x.tv_sec == y.tv_sec && x.tv_usec > y.tv_usec))
+#define timeval_is_smaler(x,y) ((x.tv_sec < y.tv_sec) || (x.tv_sec == y.tv_sec && x.tv_usec < y.tv_usec))
+
+#define IOGC_FREE(NAME) void NAME(void *object)
+typedef IOGC_FREE(iogc_free);
+void iogc_add(void *object);
+void iogc_add_callback(void *object, iogc_free *free_callback);
+
+#endif
+#endif
diff --git a/src/IOHandler/IOLog.c b/src/IOHandler/IOLog.c
new file mode 100644 (file)
index 0000000..20637c1
--- /dev/null
@@ -0,0 +1,48 @@
+/* IOLog.c - IOMultiplexer v2
+ * Copyright (C) 2014  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+#define _IOHandler_internals
+#include "IOInternal.h"
+#include "IOHandler.h"
+#include "IOLog.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+
+void iolog_init() {
+
+}
+
+#define MAXLOG 1024
+
+void iolog_trigger(enum IOLogType type, char *text, ...) {
+    va_list arg_list;
+    char logBuf[MAXLOG+1];
+    int pos;
+    logBuf[0] = '\0';
+    va_start(arg_list, text);
+    pos = vsnprintf(logBuf, MAXLOG - 1, text, arg_list);
+    va_end(arg_list);
+    if (pos < 0 || pos > (MAXLOG - 1)) pos = MAXLOG - 1;
+    logBuf[pos] = '\n';
+    logBuf[pos+1] = '\0';
+    
+    printf("%s", logBuf);
+}
+
+void iolog_register_callback(iolog_callback *callback) {
+
+}
diff --git a/src/IOHandler/IOLog.h b/src/IOHandler/IOLog.h
new file mode 100644 (file)
index 0000000..451155e
--- /dev/null
@@ -0,0 +1,41 @@
+/* IOLog.h - IOMultiplexer v2
+ * Copyright (C) 2014  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+#ifndef _IOLog_h
+#define _IOLog_h
+#ifndef _IOHandler_internals
+#include "IOHandler.h"
+#else
+enum IOLogType;
+
+void iolog_init();
+void iolog_trigger(enum IOLogType type, char *text, ...);
+
+#endif
+
+enum IOLogType {
+    IOLOG_DEBUG,
+    IOLOG_WARNING,
+    IOLOG_ERROR,
+    IOLOG_FATAL
+};
+
+#define IOLOG_CALLBACK(NAME) void NAME(enum IOLogType type, char *message)
+typedef IOLOG_CALLBACK(iolog_callback);
+
+void iolog_register_callback(iolog_callback *callback);
+
+#endif
diff --git a/src/IOHandler/IOSockets.c b/src/IOHandler/IOSockets.c
new file mode 100644 (file)
index 0000000..1973ea4
--- /dev/null
@@ -0,0 +1,978 @@
+/* IOSockets.c - IOMultiplexer v2
+ * Copyright (C) 2014  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+#define _IOHandler_internals
+#include "IOInternal.h"
+#include "IOHandler.h"
+#include "IOSockets.h"
+#include "IOLog.h"
+#include "IODNSLookup.h"
+
+#ifdef WIN32
+#define _WIN32_WINNT 0x501
+#include <windows.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h> 
+#include <arpa/inet.h>
+#include <unistd.h>
+#endif
+#include "compat/inet.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+#include <stdarg.h>
+
+#ifndef EWOULDBLOCK
+#define EWOULDBLOCK EAGAIN
+#endif
+
+struct _IOSocket *iosocket_first = NULL;
+struct _IOSocket *iosocket_last = NULL;
+
+struct IOEngine *engine = NULL;
+
+static void iosocket_activate(struct _IOSocket *iosock);
+static void iosocket_deactivate(struct _IOSocket *iosock);
+static void iosocket_increase_buffer(struct IOSocketBuffer *iobuf, size_t required);
+static int iosocket_parse_address(const char *hostname, struct IODNSAddress *addr, int records);
+static int iosocket_lookup_hostname(struct _IOSocket *iosock, const char *hostname, int records, int bindaddr);
+static int iosocket_lookup_apply(struct _IOSocket *iosock, int noip6);
+static void iosocket_connect_finish(struct _IOSocket *iosock);
+static void iosocket_listen_finish(struct _IOSocket *iosock);
+static int iosocket_try_write(struct _IOSocket *iosock);
+
+#ifdef WIN32
+static int close(int fd) {
+       return closesocket(fd);
+}
+#endif
+
+static void iosockets_init_engine() {
+       //try other engines
+       if(!engine && engine_kevent.init && engine_kevent.init())
+               engine = &engine_kevent;
+       if(!engine && engine_epoll.init && engine_epoll.init())
+               engine = &engine_epoll;
+       if(!engine && engine_win32.init && engine_win32.init())
+               engine = &engine_win32;
+       
+       if (!engine) {
+               if(engine_select.init())
+                       engine = &engine_select;
+               else {
+                       iolog_trigger(IOLOG_FATAL, "found no useable IO engine");
+                       return;
+               }
+       }
+       iolog_trigger(IOLOG_DEBUG, "using %s IOSockets engine", engine->name);
+}
+
+void _init_sockets() {
+       #ifdef WIN32
+       WSADATA wsaData;
+    int iResult;
+       //Initialize Winsock
+    iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
+    if(iResult != 0){
+        iolog_trigger(IOLOG_ERROR, "WSAStartup returned error code: %d", iResult);
+    }
+       #endif
+       
+       iosockets_init_engine();
+}
+
+
+struct _IOSocket *_create_socket() {
+       struct _IOSocket *iosock = calloc(1, sizeof(*iosock));
+       if(!iosock) {
+               iolog_trigger(IOLOG_ERROR, "could not allocate memory for _IOSocket in %s:%d", __FILE__, __LINE__);
+               return NULL;
+       }
+       if(iosocket_last)
+               iosocket_last->next = iosock;
+       else
+               iosocket_first = iosock;
+       iosock->prev = iosocket_last;
+       iosocket_last = iosock;
+       return iosock;
+}
+
+void _free_socket(struct _IOSocket *iosock) {
+       iosocket_deactivate(iosock);
+       if(iosock->prev)
+               iosock->prev->next = iosock->next;
+       else
+               iosocket_first = iosock->next;
+       if(iosock->next)
+               iosock->next->prev = iosock->prev;
+       else
+               iosocket_last = iosock->prev;
+       
+       if(iosock->bind.addr.addresslen)
+               free(iosock->bind.addr.address);
+       if(iosock->dest.addr.addresslen)
+               free(iosock->dest.addr.address);
+       if(iosock->readbuf.buffer)
+               free(iosock->readbuf.buffer);
+       if(iosock->writebuf.buffer)
+               free(iosock->writebuf.buffer);
+       
+       free(iosock);
+}
+
+static void iosocket_activate(struct _IOSocket *iosock) {
+       if((iosock->socket_flags & IOSOCKETFLAG_ACTIVE))
+               return;
+       iosock->socket_flags |= IOSOCKETFLAG_ACTIVE;
+       engine->add(iosock);
+}
+
+static void iosocket_deactivate(struct _IOSocket *iosock) {
+       if(!(iosock->socket_flags & IOSOCKETFLAG_ACTIVE))
+               return;
+       iosock->socket_flags &= ~IOSOCKETFLAG_ACTIVE;
+       engine->remove(iosock);
+}
+
+static void iosocket_increase_buffer(struct IOSocketBuffer *iobuf, size_t required) {
+       if(iobuf->buflen >= required) return;
+       char *new_buf;
+       if(iobuf->buffer)
+               new_buf = realloc(iobuf->buffer, required + 2);
+       else
+               new_buf = malloc(required + 2);
+       if(new_buf) {
+               iobuf->buffer = new_buf;
+               iobuf->buflen = required;
+       }
+}
+
+static int iosocket_parse_address(const char *hostname, struct IODNSAddress *addr, int records) {
+       int ret;
+       if((records & IOSOCKET_ADDR_IPV4)) {
+               struct sockaddr_in ip4addr;
+               ret = inet_pton(AF_INET, hostname, &(ip4addr.sin_addr));
+               if(ret == 1) {
+                       addr->addresslen = sizeof(ip4addr);
+                       addr->address = malloc(addr->addresslen);
+                       if(!addr->address) {
+                               iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__);
+                               return -1;
+                       }
+                       memcpy(addr->address, &ip4addr, sizeof(ip4addr));
+                       return 1;
+               }
+       }
+       if((records & IOSOCKET_ADDR_IPV6)) {
+               struct sockaddr_in6 ip6addr;
+               ret = inet_pton(AF_INET6, hostname, &(ip6addr.sin6_addr));
+               if(ret == 1) {
+                       addr->addresslen = sizeof(ip6addr);
+                       addr->address = malloc(addr->addresslen);
+                       if(!addr->address) {
+                               iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__);
+                               return -1;
+                       }
+                       memcpy(addr->address, &ip6addr, sizeof(ip6addr));
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+static int iosocket_lookup_hostname(struct _IOSocket *iosock, const char *hostname, int records, int bindaddr) {
+       struct IOSocketDNSLookup *lookup = calloc(1, sizeof(*lookup));
+       if(!lookup) {
+               iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOSocketDNSLookup in %s:%d", __FILE__, __LINE__);
+               return 0;
+       }
+       
+       struct _IODNSQuery *query = _create_dnsquery();
+       if(!query) {
+               free(lookup);
+               return 0;
+       }
+       
+       query->parent = lookup;
+       query->flags |= IODNSFLAG_PARENT_SOCKET;
+       lookup->iosocket = iosock;
+       lookup->query = query;
+       strncpy(lookup->hostname, hostname, sizeof(lookup->hostname));
+       lookup->hostname[sizeof(lookup->hostname)-1] = 0;
+       if(bindaddr) {
+               lookup->bindlookup = 1;
+               iosock->bind.addrlookup = lookup;
+       } else {
+               lookup->bindlookup = 0;
+               iosock->dest.addrlookup = lookup;
+       }
+       
+       int dnsrecords = 0;
+       if((records & IOSOCKET_ADDR_IPV4))
+               dnsrecords |= IODNS_RECORD_A;
+       if((records & IOSOCKET_ADDR_IPV6))
+               dnsrecords |= IODNS_RECORD_AAAA;
+       
+       query->request.host = strdup(hostname);
+       query->type = (dnsrecords & IODNS_FORWARD);
+       
+       _start_dnsquery(query);
+       return 1;
+}
+
+void iosocket_lookup_callback(struct IOSocketDNSLookup *lookup, struct IODNSEvent *event) {
+       lookup->query = NULL;
+       struct _IOSocket *iosock = lookup->iosocket;
+       if(iosock == NULL)
+               return;
+       
+       if(event->type == IODNSEVENT_SUCCESS)
+               lookup->result = event->result;
+       else
+               lookup->result = NULL;
+       
+       if(lookup->bindlookup) {
+               iosock->socket_flags &= ~IOSOCKETFLAG_PENDING_BINDDNS;
+               iosock->socket_flags |= IOSOCKETFLAG_DNSDONE_BINDDNS;
+       } else {
+               iosock->socket_flags &= ~IOSOCKETFLAG_PENDING_DESTDNS;
+               iosock->socket_flags |= IOSOCKETFLAG_DNSDONE_DESTDNS;
+       }
+       
+       int dns_finished = 0;
+       if((iosock->socket_flags & (IOSOCKETFLAG_PENDING_BINDDNS | IOSOCKETFLAG_PENDING_DESTDNS)) == 0)
+               dns_finished = 1;
+       
+       if(dns_finished) {
+               int ret;
+               ret = iosocket_lookup_apply(iosock, 0);
+               if(ret) { //if ret=0 an error occured in iosocket_lookup_apply and we should stop here.
+                       if((iosock->socket_flags & IOSOCKETFLAG_LISTENING))
+                               iosocket_listen_finish(iosock);
+                       else
+                               iosocket_connect_finish(iosock);
+               }
+       }
+}
+
+static int iosocket_lookup_apply(struct _IOSocket *iosock, int noip6) {
+       char errbuf[512];
+       struct IOSocketDNSLookup *bind_lookup = ((iosock->socket_flags & IOSOCKETFLAG_DNSDONE_BINDDNS) ? iosock->bind.addrlookup : NULL);
+       struct IOSocketDNSLookup *dest_lookup = ((iosock->socket_flags & IOSOCKETFLAG_DNSDONE_DESTDNS) ? iosock->dest.addrlookup : NULL);
+       
+       iolog_trigger(IOLOG_DEBUG, "all pending lookups finished. trying to apply lookup results...");
+       
+       if(!bind_lookup && !dest_lookup) {
+               iosock->socket_flags |= IOSOCKETFLAG_DNSERROR;
+               sprintf(errbuf, "Internal Error");
+               iolog_trigger(IOLOG_ERROR, "trying to apply lookup results without any lookups processed in %s:%d", __FILE__, __LINE__);
+               goto iosocket_lookup_clear;
+       }
+       
+       struct IODNSResult *result;
+       int bind_numip4 = 0, bind_numip6 = 0;
+       int dest_numip4 = 0, dest_numip6 = 0;
+       
+       if(bind_lookup) {
+               for(result = bind_lookup->result; result; result = result->next) {
+                       if((result->type & IODNS_RECORD_A))
+                               bind_numip4++;
+                       if((result->type & IODNS_RECORD_AAAA))
+                               bind_numip6++;
+               }
+       }
+       if(dest_lookup) {
+               for(result = dest_lookup->result; result; result = result->next) {
+                       if((result->type & IODNS_RECORD_A))
+                               dest_numip4++;
+                       if((result->type & IODNS_RECORD_AAAA))
+                               dest_numip6++;
+               }
+       }
+       int useip6 = 0;
+       int useip4 = 0;
+       if(bind_lookup && (bind_numip6 == 0 && bind_numip4 == 0)) {
+               iosock->socket_flags |= IOSOCKETFLAG_DNSERROR;
+               sprintf(errbuf, "could not lookup bind address (%s)", bind_lookup->hostname);
+               goto iosocket_lookup_clear;
+       } else if(dest_lookup && (dest_numip6 == 0 && dest_numip4 == 0)) {
+               iosock->socket_flags |= IOSOCKETFLAG_DNSERROR;
+               sprintf(errbuf, "could not lookup destination address (%s)", dest_lookup->hostname);
+               goto iosocket_lookup_clear;
+       } else if(bind_lookup && dest_lookup) {
+               if(bind_numip6 > 0 && dest_numip6 > 0)
+                       useip6 = 1;
+               else if(bind_numip4 > 0 && dest_numip4 > 0)
+                       useip4 = 1;
+               else {
+                       iosock->socket_flags |= IOSOCKETFLAG_DNSERROR;
+                       sprintf(errbuf, "could not lookup adresses of the same IP family for bind and destination host. (bind: %d ip4, %d ip6 | dest: %d ip4, %d ip6)", bind_numip4, bind_numip6, dest_numip4, dest_numip6);
+                       goto iosocket_lookup_clear;
+               }
+       } else if(bind_lookup) {
+               if(bind_numip6)
+                       useip6 = 1;
+               else if(bind_numip4)
+                       useip4 = 1;
+       } else if(dest_lookup) {
+               if(dest_numip6)
+                       useip6 = 1;
+               else if(dest_numip4)
+                       useip4 = 1;
+       }
+       
+       int usetype = 0;
+       if(useip6) {
+               usetype = IODNS_RECORD_AAAA;
+               iosock->socket_flags |= IOSOCKETFLAG_IPV6SOCKET;
+       } else if(useip4) {
+               usetype = IODNS_RECORD_A;
+       } else {
+               //should already be handled
+       }
+       
+       #define IOSOCKET_APPLY_COPYADDR(type) \
+       iosock->type.addr.addresslen = result->result.addr.addresslen; \
+       iosock->type.addr.address = malloc(result->result.addr.addresslen); \
+       if(!iosock->type.addr.address) { \
+               iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__); \
+               iosock->type.addr.addresslen = 0; \
+               iosock->socket_flags |= IOSOCKETFLAG_DNSERROR; \
+               sprintf(errbuf, "could not allocate memory for dns information"); \
+               goto iosocket_lookup_clear; \
+       } \
+       memcpy(iosock->type.addr.address, result->result.addr.address, result->result.addr.addresslen);
+       
+       
+       if(bind_lookup) {
+               int usenum = (useip6 ? bind_numip6 : bind_numip4);
+               usenum = rand() % usenum;
+               for(result = bind_lookup->result; result; result = result->next) {
+                       if((result->type & usetype)) {
+                               if(usenum == 0) {
+                                       inet_ntop((useip6 ? AF_INET6 : AF_INET), (useip6 ? (void *)(&((struct sockaddr_in6 *)result->result.addr.address)->sin6_addr) : (void *)(&((struct sockaddr_in *)result->result.addr.address)->sin_addr)), errbuf, sizeof(errbuf));
+                                       iolog_trigger(IOLOG_DEBUG, "using IPv%s Address (%s) as bind address", (useip6 ? "6" : "4"), errbuf);
+                                       IOSOCKET_APPLY_COPYADDR(bind)
+                                       break;
+                               }
+                               usenum--;
+                       }
+               }
+       } else
+               iosock->bind.addr.addresslen = 0;
+       
+       if(dest_lookup) {
+               int usenum = (useip6 ? dest_numip6 : dest_numip4);
+               usenum = rand() % usenum;
+               for(result = dest_lookup->result; result; result = result->next) {
+                       if((result->type & usetype)) {
+                               if(usenum == 0) {
+                                       inet_ntop((useip6 ? AF_INET6 : AF_INET), (useip6 ? (void *)(&((struct sockaddr_in6 *)result->result.addr.address)->sin6_addr) : (void *)(&((struct sockaddr_in *)result->result.addr.address)->sin_addr)), errbuf, sizeof(errbuf));
+                                       iolog_trigger(IOLOG_DEBUG, "using IPv%s Address (%s) as dest address", (useip6 ? "6" : "4"), errbuf);
+                                       IOSOCKET_APPLY_COPYADDR(dest)
+                                       break;
+                               }
+                               usenum--;
+                       }
+               }
+       } else
+               iosock->dest.addr.addresslen = 0;
+       
+       iosocket_lookup_clear:
+       if(bind_lookup) {
+               if(bind_lookup->result)
+                       iodns_free_result(bind_lookup->result);
+               free(bind_lookup);
+       }
+       if(dest_lookup) {
+               if(dest_lookup->result)
+                       iodns_free_result(dest_lookup->result);
+               free(dest_lookup);
+       }
+       
+       if((iosock->socket_flags & IOSOCKETFLAG_DNSERROR)) {
+               // TODO: trigger error
+               
+               return 0;
+       } else
+               return 1;
+}
+
+static void iosocket_prepare_fd(int sockfd) {
+       // prevent SIGPIPE
+       #ifndef WIN32
+       #if defined(SO_NOSIGPIPE)
+       {
+               int set = 1;
+               setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
+       }
+       #else
+       signal(SIGPIPE, SIG_IGN);
+       #endif
+       #endif
+       
+       // make sockfd unblocking
+       #if defined(F_GETFL)
+       {
+               int fcntl_flags;
+               fcntl_flags = fcntl(sockfd, F_GETFL);
+               fcntl(sockfd, F_SETFL, fcntl_flags|O_NONBLOCK);
+               fcntl_flags = fcntl(sockfd, F_GETFD);
+               fcntl(sockfd, F_SETFD, fcntl_flags|FD_CLOEXEC);
+       }
+       #else
+       /* I hope you're using the Win32 backend or something else that
+        * automatically marks the file descriptor non-blocking...
+        */
+       #endif
+}
+
+static void iosocket_connect_finish(struct _IOSocket *iosock) {
+       int sockfd;
+       if((iosock->socket_flags & IOSOCKETFLAG_IPV6SOCKET))
+               sockfd = socket(AF_INET6, SOCK_STREAM, 0);
+       else
+               sockfd = socket(AF_INET, SOCK_STREAM, 0);
+       if(sockfd == -1) {
+               iolog_trigger(IOLOG_ERROR, "could not create socket in %s:%d", __FILE__, __LINE__);
+               // TODO: trigger error
+               
+               return;
+       }
+       
+       // set port and bind address
+       if((iosock->socket_flags & IOSOCKETFLAG_IPV6SOCKET)) {
+               struct sockaddr_in6 *ip6 = (void*) iosock->dest.addr.address;
+               ip6->sin6_family = AF_INET6;
+               ip6->sin6_port = htons(iosock->port);
+               
+               if(iosock->bind.addr.addresslen) {
+                       struct sockaddr_in6 *ip6bind = (void*) iosock->bind.addr.address;
+                       ip6bind->sin6_family = AF_INET6;
+                       ip6bind->sin6_port = htons(0);
+                       
+                       bind(sockfd, (struct sockaddr*)ip6bind, sizeof(*ip6bind));
+               }
+       } else {
+               struct sockaddr_in *ip4 = (void*) iosock->dest.addr.address;
+               ip4->sin_family = AF_INET;
+               ip4->sin_port = htons(iosock->port);
+               
+               if(iosock->bind.addr.addresslen) {
+                       struct sockaddr_in *ip4bind = (void*) iosock->bind.addr.address;
+                       ip4bind->sin_family = AF_INET;
+                       ip4bind->sin_port = htons(0);
+                       
+                       bind(sockfd, (struct sockaddr*)ip4bind, sizeof(*ip4bind));
+               }
+       }
+       
+       iosocket_prepare_fd(sockfd);
+       
+       connect(sockfd, iosock->dest.addr.address, iosock->dest.addr.addresslen); //returns EINPROGRESS here (nonblocking)
+       iosock->fd = sockfd;
+       iosock->socket_flags |= IOSOCKETFLAG_CONNECTING;
+       
+       iosocket_activate(iosock);
+}
+
+static void iosocket_listen_finish(struct _IOSocket *iosock) {
+       int sockfd;
+       if((iosock->socket_flags & IOSOCKETFLAG_IPV6SOCKET))
+               sockfd = socket(AF_INET6, SOCK_STREAM, 0);
+       else
+               sockfd = socket(AF_INET, SOCK_STREAM, 0);
+       if(sockfd == -1) {
+               iolog_trigger(IOLOG_ERROR, "could not create socket in %s:%d", __FILE__, __LINE__);
+               // TODO: trigger error
+               
+               return;
+       }
+       
+       // set port and bind address
+       if((iosock->socket_flags & IOSOCKETFLAG_IPV6SOCKET)) {
+               struct sockaddr_in6 *ip6bind = (void*) iosock->bind.addr.address;
+               ip6bind->sin6_family = AF_INET6;
+               ip6bind->sin6_port = htons(0);
+               
+               int opt = 1;
+               setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt));
+               
+               bind(sockfd, (struct sockaddr*)ip6bind, sizeof(*ip6bind));
+       } else {
+               struct sockaddr_in *ip4bind = (void*) iosock->bind.addr.address;
+               ip4bind->sin_family = AF_INET;
+               ip4bind->sin_port = htons(0);
+               
+               int opt = 1;
+               setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt));
+               
+               bind(sockfd, (struct sockaddr*)ip4bind, sizeof(*ip4bind));
+       }
+       
+       iosocket_prepare_fd(sockfd);
+       
+       listen(sockfd, 1);
+       iosock->fd = sockfd;
+       
+       iosocket_activate(iosock);
+}
+
+struct _IOSocket *iosocket_accept_client(struct _IOSocket *iosock) {
+       struct IOSocket *new_iosocket = calloc(1, sizeof(*new_iosocket));
+       if(!new_iosocket) {
+               iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOSocket in %s:%d", __FILE__, __LINE__);
+               close(accept(iosock->fd, NULL, 0)); // simply drop connection
+               return NULL;
+       }
+       struct _IOSocket *new_iosock = _create_socket();
+       if(!new_iosock) {
+               free(new_iosocket);
+               close(accept(iosock->fd, NULL, 0)); // simply drop connection
+               return NULL;
+       }
+       new_iosocket->iosocket = new_iosock;
+       new_iosocket->status = IOSOCKET_CONNECTED;
+       new_iosock->parent = new_iosocket;
+       new_iosock->socket_flags |= IOSOCKETFLAG_PARENT_PUBLIC | IOSOCKETFLAG_INCOMING | (iosock->socket_flags & IOSOCKETFLAG_IPV6SOCKET);
+       
+       struct sockaddr_storage addr;
+       socklen_t addrlen = sizeof(addr);
+       
+       //accept client
+       new_iosock->fd = accept(iosock->fd, (struct sockaddr *)&addr, &addrlen);
+       
+       //copy remote address
+       new_iosock->dest.addr.address = malloc(addrlen);
+       if(!new_iosock->dest.addr.address) {
+               close(new_iosock->fd);
+               free(new_iosock);
+               free(new_iosock);
+               iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__);
+               return NULL;
+       }
+       memcpy(new_iosock->dest.addr.address, &addr, addrlen);
+       new_iosock->dest.addr.addresslen = addrlen;
+       
+       //copy local address
+       new_iosock->bind.addr.address = malloc(iosock->bind.addr.addresslen);
+       if(!new_iosock->bind.addr.address) {
+               close(new_iosock->fd);
+               free(new_iosock);
+               free(new_iosock);
+               iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__);
+               return NULL;
+       }
+       memcpy(new_iosock->bind.addr.address, iosock->bind.addr.address, iosock->bind.addr.addresslen);
+       new_iosock->bind.addr.addresslen = iosock->bind.addr.addresslen;
+       
+       //prepare new socket fd
+       iosocket_prepare_fd(new_iosock->fd);
+       
+       if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) {
+               new_iosocket->ssl = 1;
+               new_iosock->socket_flags |= IOSOCKETFLAG_SSLSOCKET;
+               //TODO: SSL Handshake
+       }
+       
+       iosocket_activate(new_iosock);
+       return new_iosock;
+}
+
+/* public functions */
+
+struct IOSocket *iosocket_connect(const char *hostname, unsigned int port, int ssl, const char *bindhost, iosocket_callback *callback) {
+       return iosocket_connect_flags(hostname, port, ssl, bindhost, callback, (IOSOCKET_ADDR_IPV4 | IOSOCKET_ADDR_IPV6));
+}
+
+struct IOSocket *iosocket_connect_flags(const char *hostname, unsigned int port, int ssl, const char *bindhost, iosocket_callback *callback, int flags) {
+       struct IOSocket *iodescriptor = calloc(1, sizeof(*iodescriptor));
+       if(!iodescriptor) {
+               iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOSocket in %s:%d", __FILE__, __LINE__);
+               return NULL;
+       }
+       
+       struct _IOSocket *iosock = _create_socket();
+       if(!iosock) {
+               free(iodescriptor);
+               return NULL;
+       }
+       
+       iodescriptor->iosocket = iosock;
+       iodescriptor->status = IOSOCKET_CONNECTING;
+       iodescriptor->callback = callback;
+       iosock->parent = iodescriptor;
+       iosock->socket_flags |= IOSOCKETFLAG_PARENT_PUBLIC;
+       iosock->port = port;
+       if(ssl) {
+               iodescriptor->ssl = 1;
+               iosock->socket_flags |= IOSOCKETFLAG_SSLSOCKET;
+       }
+       
+       if(bindhost) {
+               switch(iosocket_parse_address(bindhost, &iosock->bind.addr, flags)) {
+               case -1:
+                       free(iosock);
+                       return NULL;
+               case 0:
+                       /* start dns lookup */
+                       iosock->socket_flags |= IOSOCKETFLAG_PENDING_BINDDNS;
+                       iosocket_lookup_hostname(iosock, bindhost, flags, 1);
+                       break;
+               case 1:
+                       /* valid address */
+                       break;
+               }
+       }
+       switch(iosocket_parse_address(hostname, &iosock->dest.addr, flags)) {
+       case -1:
+               free(iosock);
+               return NULL;
+       case 0:
+               /* start dns lookup */
+               iosock->socket_flags |= IOSOCKETFLAG_PENDING_DESTDNS;
+               iosocket_lookup_hostname(iosock, hostname, flags, 0);
+               break;
+       case 1:
+               /* valid address */
+               break;
+       }
+       if((iosock->socket_flags & (IOSOCKETFLAG_PENDING_BINDDNS | IOSOCKETFLAG_PENDING_DESTDNS)) == 0) {
+               iosocket_connect_finish(iosock);
+       }
+       return iodescriptor;
+}
+
+struct IOSocket *iosocket_listen(const char *hostname, unsigned int port, iosocket_callback *callback) {
+       return iosocket_listen_flags(hostname, port, callback, (IOSOCKET_ADDR_IPV4 | IOSOCKET_ADDR_IPV6));
+}
+
+struct IOSocket *iosocket_listen_flags(const char *hostname, unsigned int port, iosocket_callback *callback, int flags) {
+       struct IOSocket *iodescriptor = calloc(1, sizeof(*iodescriptor));
+       if(!iodescriptor) {
+               iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOSocket in %s:%d", __FILE__, __LINE__);
+               return NULL;
+       }
+       
+       struct _IOSocket *iosock = _create_socket();
+       if(!iosock) {
+               free(iodescriptor);
+               return NULL;
+       }
+       
+       iodescriptor->iosocket = iosock;
+       iodescriptor->status = IOSOCKET_LISTENING;
+       iodescriptor->listening = 1;
+       iodescriptor->callback = callback;
+       iosock->parent = iodescriptor;
+       iosock->socket_flags |= IOSOCKETFLAG_PARENT_PUBLIC | IOSOCKETFLAG_LISTENING;
+       iosock->port = port;
+       /*
+       if(ssl) {
+               iodescriptor->ssl = 1;
+               iosock->socket_flags |= IOSOCKETFLAG_SSLSOCKET;
+       }
+       */
+       
+       switch(iosocket_parse_address(hostname, &iosock->bind.addr, flags)) {
+       case -1:
+               free(iosock);
+               return NULL;
+       case 0:
+               /* start dns lookup */
+               iosock->socket_flags |= IOSOCKETFLAG_PENDING_BINDDNS;
+               iosocket_lookup_hostname(iosock, hostname, flags, 1);
+               break;
+       case 1:
+               /* valid address */
+               break;
+       }
+       if((iosock->socket_flags & IOSOCKETFLAG_PENDING_BINDDNS) == 0) {
+               iosocket_listen_finish(iosock);
+       }
+       return iodescriptor;
+}
+
+struct IOSocket *iosocket_listen_ssl(const char *hostname, unsigned int port, const char *certfile, const char *keyfile, iosocket_callback *callback) {
+       return iosocket_listen_ssl_flags(hostname, port, certfile, keyfile, callback, (IOSOCKET_ADDR_IPV4 | IOSOCKET_ADDR_IPV6));
+}
+
+struct IOSocket *iosocket_listen_ssl_flags(const char *hostname, unsigned int port, const char *certfile, const char *keyfile, iosocket_callback *callback, int flags) {
+       //TODO: SSL
+       return NULL;
+}
+
+void iosocket_close(struct IOSocket *iosocket) {
+       struct _IOSocket *iosock = iosocket->iosocket;
+       if(iosock == NULL) {
+               iolog_trigger(IOLOG_WARNING, "called iosocket_close for destroyed IOSocket in %s:%d", __FILE__, __LINE__);
+               return;
+       }
+       
+       iosock->socket_flags |= IOSOCKETFLAG_SHUTDOWN;
+       
+       if(iosock->writebuf.bufpos) {
+               //try to send everything before closing
+#if defined(F_GETFL)
+               {
+                       int flags;
+                       flags = fcntl(iosock->fd, F_GETFL);
+                       fcntl(iosock->fd, F_SETFL, flags & ~O_NONBLOCK);
+                       flags = fcntl(iosock->fd, F_GETFD);
+                       fcntl(iosock->fd, F_SETFD, flags|FD_CLOEXEC);
+               }
+#else
+               iosocket_deactivate(iosock);
+#endif
+               iosocket_try_write(iosock);
+       }
+       //close IOSocket
+       if(iosock->sslnode) {
+               //TODO: SSL
+       }
+       if(iosock->fd)
+               close(iosock->fd);
+       _free_socket(iosock);
+       iosocket->iosocket = NULL;
+       iosocket->status = IOSOCKET_CLOSED;
+       iogc_add(iosocket);
+}
+
+static int iosocket_try_write(struct _IOSocket *iosock) {
+       if(!iosock->writebuf.bufpos) return 0;
+       iolog_trigger(IOLOG_DEBUG, "write writebuf (%d bytes) to socket (fd: %d)", iosock->writebuf.bufpos, iosock->fd);
+       int res;
+       if(iosock->sslnode) {
+               /* res = iohandler_ssl_write(iofd, iofd->writebuf.buffer, iofd->writebuf.bufpos); */
+               // TODO
+       } else
+               res = send(iosock->fd, iosock->writebuf.buffer, iosock->writebuf.bufpos, 0);
+       if(res < 0) {
+               if (errno != EAGAIN && errno != EWOULDBLOCK)
+                       iolog_trigger(IOLOG_ERROR, "could not write to socket (fd: %d): %d - %s", iosock->fd, errno, strerror(errno));
+               else
+                       res = 0;
+       } else {
+               iosock->writebuf.bufpos -= res;
+               if((iosock->socket_flags & (IOSOCKETFLAG_ACTIVE & IOSOCKETFLAG_SHUTDOWN)) == IOSOCKETFLAG_ACTIVE)
+                       engine->update(iosock);
+       }
+       return res;
+}
+
+void iosocket_send(struct IOSocket *iosocket, const char *data, size_t datalen) {
+       struct _IOSocket *iosock = iosocket->iosocket;
+       if(iosock == NULL) {
+               iolog_trigger(IOLOG_WARNING, "called iosocket_close for destroyed IOSocket in %s:%d", __FILE__, __LINE__);
+               return;
+       }
+       if(iosock->socket_flags & IOSOCKETFLAG_SHUTDOWN) {
+               iolog_trigger(IOLOG_ERROR, "could not write to socket (socket is closing)");
+               return;
+       }
+       iolog_trigger(IOLOG_DEBUG, "add %d to writebuf (fd: %d): %s", datalen, iosock->fd, data);
+       if(iosock->writebuf.buflen < iosock->writebuf.bufpos + datalen) {
+               iolog_trigger(IOLOG_DEBUG, "increase writebuf (curr: %d) to %d (+%d bytes)", iosock->writebuf.buflen, iosock->writebuf.bufpos + datalen, (iosock->writebuf.bufpos + datalen - iosock->writebuf.buflen));
+               iosocket_increase_buffer(&iosock->writebuf, iosock->writebuf.bufpos + datalen);
+               if(iosock->writebuf.buflen < iosock->writebuf.bufpos + datalen) {
+                       iolog_trigger(IOLOG_ERROR, "increase writebuf (curr: %d) to %d (+%d bytes) FAILED", iosock->writebuf.buflen, iosock->writebuf.bufpos + datalen, (iosock->writebuf.bufpos + datalen - iosock->writebuf.buflen));
+                       return;
+               }
+       }
+       memcpy(iosock->writebuf.buffer + iosock->writebuf.bufpos, data, datalen);
+       iosock->writebuf.bufpos += datalen;
+       if((iosock->socket_flags & IOSOCKETFLAG_ACTIVE))
+               engine->update(iosock);
+}
+
+void iosocket_write(struct IOSocket *iosocket, const char *line) {
+       size_t linelen = strlen(line);
+       iosocket_send(iosocket, line, linelen);
+}
+
+void iosocket_printf(struct IOSocket *iosocket, const char *text, ...) {
+       va_list arg_list;
+       char sendBuf[IOSOCKET_PRINTF_LINE_LEN];
+       int pos;
+       sendBuf[0] = '\0';
+       va_start(arg_list, text);
+       pos = vsnprintf(sendBuf, IOSOCKET_PRINTF_LINE_LEN - 2, text, arg_list);
+       va_end(arg_list);
+       if (pos < 0 || pos > (IOSOCKET_PRINTF_LINE_LEN - 2)) pos = IOSOCKET_PRINTF_LINE_LEN - 2;
+       sendBuf[pos] = '\n';
+       sendBuf[pos+1] = '\0';
+       iosocket_send(iosocket, sendBuf, pos+1);
+}
+
+
+
+static void iosocket_trigger_event(struct IOSocketEvent *event) {
+       if(!event->socket->callback) 
+               return;
+       iolog_trigger(IOLOG_DEBUG, "triggering event");
+       event->socket->callback(event);
+}
+
+void iosocket_events_callback(struct _IOSocket *iosock, int readable, int writeable) {
+       if((iosock->socket_flags & IOSOCKETFLAG_PARENT_PUBLIC)) {
+               struct IOSocket *iosocket = iosock->parent;
+               struct IOSocketEvent callback_event;
+               callback_event.type = IOSOCKETEVENT_IGNORE;
+               callback_event.socket = iosocket;
+               
+               if((iosock->socket_flags & IOSOCKETFLAG_SSL_HANDSHAKE)) {
+                       //TODO: SSL
+               } else if((iosock->socket_flags & IOSOCKETFLAG_LISTENING)) {
+                       if(readable) {
+                               //new client connected
+                               struct _IOSocket *new_iosock = iosocket_accept_client(iosock);
+                               if(!new_iosock)
+                                       return;
+                               
+                               if(!(new_iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) {
+                                       callback_event.type = IOSOCKETEVENT_ACCEPT;
+                                       callback_event.data.accept_socket = new_iosock->parent;
+                               }
+                       }
+                       
+               } else if((iosock->socket_flags & IOSOCKETFLAG_CONNECTING)) {
+                       if(readable) { //could not connect
+                               callback_event.type = IOSOCKETEVENT_NOTCONNECTED;
+                               /*
+                               socklen_t arglen = sizeof(callback_event.data.errid);
+                               if (getsockopt(iosock->fd, SOL_SOCKET, SO_ERROR, &callback_event.data.errid, &arglen) < 0)
+                                       callback_event.data.errid = errno;
+                               */
+                               iosock->socket_flags |= IOSOCKETFLAG_DEAD;
+                       } else if(writeable) { //connection established
+                               iosocket->status = IOSOCKET_CONNECTED;
+                               if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) {
+                                       //TODO: SSL Handshake
+                                       return;
+                               }
+                               
+                               callback_event.type = IOSOCKETEVENT_CONNECTED;
+                               iosock->socket_flags &= ~IOSOCKETFLAG_CONNECTING;
+                               engine->update(iosock);
+                               
+                               //initialize readbuf
+                               iosocket_increase_buffer(&iosock->readbuf, 1024);
+                       }
+               } else {
+                       if(readable) {
+                               int bytes;
+                               if(iosock->readbuf.buflen - iosock->readbuf.bufpos >= 128)
+                                       iosocket_increase_buffer(&iosock->readbuf, iosock->readbuf.buflen + 1024);
+                               if((iosock->socket_flags & IOSOCKETFLAG_SSLSOCKET)) {
+                                       //TODO: SSL read
+                               } else 
+                                       bytes = recv(iosock->fd, iosock->readbuf.buffer + iosock->readbuf.bufpos, iosock->readbuf.buflen - iosock->readbuf.bufpos, 0);
+                                       
+                               if(bytes <= 0) {
+                                       if (errno != EAGAIN || errno != EWOULDBLOCK) {
+                                               iosock->socket_flags |= IOSOCKETFLAG_DEAD;
+                                               
+                                               callback_event.type = IOSOCKETEVENT_CLOSED;
+                                               callback_event.data.errid = errno;
+                                       }
+                               } else {
+                                       int i;
+                                       iolog_trigger(IOLOG_DEBUG, "received %d bytes (fd: %d). readbuf position: %d", bytes, iosock->fd, iosock->readbuf.bufpos);
+                                       iosock->readbuf.bufpos += bytes;
+                                       callback_event.type = IOSOCKETEVENT_RECV;
+                                       
+                                       if(iosocket->parse_delimiter) {
+                                               int j, used_bytes = 0;
+                                               for(i = 0; i < iosock->readbuf.bufpos; i++) {
+                                                       int is_delimiter = 0;
+                                                       for(j = 0; j < IOSOCKET_PARSE_DELIMITERS_COUNT; j++) {
+                                                               if(iosock->readbuf.buffer[i] == iosocket->delimiters[j]) {
+                                                                       is_delimiter = 1;
+                                                                       break;
+                                                               }
+                                                       }
+                                                       if(is_delimiter) {
+                                                               iosock->readbuf.buffer[i] = 0;
+                                                               callback_event.data.recv_str = iosock->readbuf.buffer + used_bytes;
+                                                               iolog_trigger(IOLOG_DEBUG, "parsed line (%d bytes): %s", i - used_bytes, iosock->readbuf.buffer + used_bytes);
+                                                               used_bytes = i+1;
+                                                               if(iosock->readbuf.buffer[i-1] != 0 || iosocket->parse_empty)
+                                                                       iosocket_trigger_event(&callback_event);
+                                                       }
+                                                       #ifdef IOSOCKET_PARSE_LINE_LIMIT
+                                                       else if(i + 1 - used_bytes >= IOSOCKET_PARSE_LINE_LIMIT) {
+                                                               iosock->readbuf.buffer[i] = 0;
+                                                               callback_event.data.recv_str = iosock->readbuf.buffer + used_bytes;
+                                                               iolog_trigger(IOLOG_DEBUG, "parsed and stripped line (%d bytes): %s", i - used_bytes, iosock->readbuf.buffer + used_bytes);
+                                                               for(; i < iosock->readbuf.bufpos; i++) { //skip the rest of the line
+                                                                       is_delimiter = 0;
+                                                                       if(iosock->readbuf.buffer[i] == iosocket->delimiters[j])
+                                                                               break;
+                                                               }
+                                                               used_bytes = i+1;
+                                                               iosocket_trigger_event(&callback_event);
+                                                       }
+                                                       #endif
+                                               }
+                                               if(used_bytes) {
+                                                       if(used_bytes == iosock->readbuf.bufpos) {
+                                                               iosock->readbuf.bufpos = 0;
+                                                               iolog_trigger(IOLOG_DEBUG, "readbuf fully processed (set buffer position to 0)");
+                                                       } else {
+                                                               iolog_trigger(IOLOG_DEBUG, "readbuf rest: %d bytes (used %d bytes)", iosock->readbuf.bufpos - used_bytes, used_bytes);
+                                                               memmove(iosock->readbuf.buffer, iosock->readbuf.buffer + used_bytes, iosock->readbuf.bufpos - used_bytes);
+                                                               iosock->readbuf.bufpos -= used_bytes;
+                                                       }
+                                               }
+                                               callback_event.type = IOSOCKETEVENT_IGNORE;
+                                       } else
+                                               callback_event.data.recv_buf = &iosock->readbuf;
+                               }
+                       }
+                       if(writeable) {
+                               int bytes;
+                               bytes = iosocket_try_write(iosock);
+                               if(bytes < 0) {
+                                       iosock->socket_flags |= IOSOCKETFLAG_DEAD;
+                                       
+                                       callback_event.type = IOSOCKETEVENT_CLOSED;
+                                       callback_event.data.errid = errno;
+                               }
+                       }
+                       
+               }
+               if(callback_event.type != IOSOCKETEVENT_IGNORE)
+                       iosocket_trigger_event(&callback_event);
+               if((iosock->socket_flags & IOSOCKETFLAG_DEAD))
+                       iosocket_close(iosocket);
+               
+       } else if((iosock->socket_flags & IOSOCKETFLAG_PARENT_DNSENGINE)) {
+               //TODO: IODNS callback
+       }
+}
+
+void iosocket_loop(int usec) {
+       struct timeval timeout;
+       timeout.tv_sec = usec / 1000000;
+       timeout.tv_usec = usec % 1000000;
+       engine->loop(&timeout);
+}
diff --git a/src/IOHandler/IOSockets.h b/src/IOHandler/IOSockets.h
new file mode 100644 (file)
index 0000000..ab36225
--- /dev/null
@@ -0,0 +1,186 @@
+/* IOSockets.h - IOMultiplexer v2
+ * Copyright (C) 2014  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+#ifndef _IOSockets_h
+#define _IOSockets_h
+#include <sys/time.h>
+#include <stddef.h>
+#include "IODNSAddress.struct.h"
+
+struct IOSocketBuffer {
+    char *buffer;
+    size_t bufpos, buflen;
+};
+
+#ifndef _IOHandler_internals
+#include "IOHandler.h"
+#else
+
+struct _IOSocket;
+struct IOSocket;
+struct IOSocketBuffer;
+struct IOSSLDescriptor;
+struct _IODNSQuery;
+struct IODNSEvent;
+
+struct IOEngine {
+    const char *name;
+    int (*init)(void);
+    void (*add)(struct _IOSocket *iosock);
+    void (*remove)(struct _IOSocket *iosock);
+    void (*update)(struct _IOSocket *iosock);
+    void (*loop)(struct timeval *timeout);
+    void (*cleanup)(void);
+};
+
+/* IO Engines */
+extern struct IOEngine engine_select; /* select system call (should always be useable) */
+extern struct IOEngine engine_kevent;
+extern struct IOEngine engine_epoll;
+extern struct IOEngine engine_win32;
+
+
+/* _IOSocket linked list */
+extern struct _IOSocket *iosocket_first;
+extern struct _IOSocket *iosocket_last;
+
+/* _IOSocket socket_flags */
+#define IOSOCKETFLAG_ACTIVE           0x0001
+#define IOSOCKETFLAG_LISTENING        0x0002
+#define IOSOCKETFLAG_PENDING_BINDDNS  0x0004
+#define IOSOCKETFLAG_PENDING_DESTDNS  0x0008
+#define IOSOCKETFLAG_DNSDONE_BINDDNS  0x0010
+#define IOSOCKETFLAG_DNSDONE_DESTDNS  0x0020
+#define IOSOCKETFLAG_DNSERROR         0x0040
+#define IOSOCKETFLAG_IPV6SOCKET       0x0080
+#define IOSOCKETFLAG_PARENT_PUBLIC    0x0100
+#define IOSOCKETFLAG_PARENT_DNSENGINE 0x0200
+#define IOSOCKETFLAG_SSLSOCKET        0x0400 /* use ssl after connecting */
+#define IOSOCKETFLAG_SSL_HANDSHAKE    0x0800 /* SSL Handshake in progress */
+#define IOSOCKETFLAG_SSL_WANTWRITE    0x1000
+#define IOSOCKETFLAG_SHUTDOWN         0x2000 /* disconnect pending */
+#define IOSOCKETFLAG_CONNECTING       0x4000
+#define IOSOCKETFLAG_INCOMING         0x8000 /* incoming (accepted) connection */
+#define IOSOCKETFLAG_DEAD            0x10000
+
+struct IOSocketDNSLookup {
+       unsigned int bindlookup : 1;
+       char hostname[256];
+       struct _IOSocket *iosocket;
+       struct _IODNSQuery *query;
+       struct IODNSResult *result;
+};
+
+struct _IOSocket {
+    int fd;
+       
+       unsigned int socket_flags : 24;
+       
+       union {
+               struct IODNSAddress addr;
+               struct IOSocketDNSLookup *addrlookup;
+       } bind;
+       union {
+               struct IODNSAddress addr;
+               struct IOSocketDNSLookup *addrlookup;
+       } dest;
+       
+       unsigned int port : 16;
+       
+       struct IOSocketBuffer readbuf;
+    struct IOSocketBuffer writebuf;
+       
+       struct IOSSLDescriptor *sslnode;
+       
+       void *parent;
+       
+       struct _IOSocket *next, *prev;
+};
+
+void _init_sockets();
+void iosocket_loop(int usec);
+void iosocket_lookup_callback(struct IOSocketDNSLookup *lookup, struct IODNSEvent *event);
+void iosocket_events_callback(struct _IOSocket *iosock, int readable, int writeable);
+
+#define iosocket_wants_writes(IOSOCK) (IOSOCK->writebuf.bufpos || (IOSOCK->socket_flags & (IOSOCKETFLAG_CONNECTING | IOSOCKETFLAG_SSL_WANTWRITE)))
+
+#endif
+
+struct IOSocketEvent;
+
+#define IOSOCKET_CALLBACK(NAME) void NAME(struct IOSocketEvent *event)
+typedef IOSOCKET_CALLBACK(iosocket_callback);
+
+enum IOSocketStatus { 
+    IOSOCKET_CLOSED, /* descriptor is dead (socket waiting for removal or timer) */
+    IOSOCKET_LISTENING, /* descriptor is waiting for connections (server socket) */
+    IOSOCKET_CONNECTING, /* descriptor is waiting for connection approval (connecting client socket) */
+    IOSOCKET_CONNECTED /* descriptor is connected (connected client socket) */
+};
+
+enum IOSocketEventType {
+    IOSOCKETEVENT_IGNORE,
+    IOSOCKETEVENT_RECV, /* client socket received something (read_lines == 1  =>  recv_str valid;  read_lines == 0  =>  recv_buf valid) */
+    IOSOCKETEVENT_CONNECTED, /* client socket connected successful */
+    IOSOCKETEVENT_NOTCONNECTED, /* client socket could not connect (errid valid) */
+    IOSOCKETEVENT_CLOSED, /* client socket lost connection (errid valid) */
+    IOSOCKETEVENT_ACCEPT, /* server socket accepted new connection (accept_socket valid) */
+    IOSOCKETEVENT_SSLFAILED, /* failed to initialize SSL session */
+       IOSOCKETEVENT_DNSFAILED /* failed to lookup DNS information */
+};
+
+struct IOSocket {
+       void *iosocket;
+       
+       enum IOSocketStatus status;
+       int listening : 1;
+       int ssl : 1;
+       int parse_delimiter : 1;
+       int parse_empty : 1; /* parse "empty" lines (only if parse_delimiter is set) */
+       unsigned char delimiters[IOSOCKET_PARSE_DELIMITERS_COUNT];
+       
+       void *data;
+       iosocket_callback *callback;
+};
+
+struct IOSocketEvent {
+    enum IOSocketEventType type;
+    struct IOSocket *socket;
+    union {
+        char *recv_str;
+               struct IOSocketBuffer *recv_buf;
+        int errid;
+        struct IOSocket *accept_socket;
+    } data;
+};
+
+
+#define IOSOCKET_ADDR_IPV4 0x01
+#define IOSOCKET_ADDR_IPV6 0x02 /* overrides IOSOCKET_ADDR_IPV4 */
+#define IOSOCKET_PROTO_UDP 0x04
+
+struct IOSocket *iosocket_connect(const char *hostname, unsigned int port, int ssl, const char *bindhost, iosocket_callback *callback);
+struct IOSocket *iosocket_connect_flags(const char *hostname, unsigned int port, int ssl, const char *bindhost, iosocket_callback *callback, int flags);
+struct IOSocket *iosocket_listen(const char *hostname, unsigned int port, iosocket_callback *callback);
+struct IOSocket *iosocket_listen_flags(const char *hostname, unsigned int port, iosocket_callback *callback, int flags);
+struct IOSocket *iosocket_listen_ssl(const char *hostname, unsigned int port, const char *certfile, const char *keyfile, iosocket_callback *callback);
+struct IOSocket *iosocket_listen_ssl_flags(const char *hostname, unsigned int port, const char *certfile, const char *keyfile, iosocket_callback *callback, int flags);
+void iosocket_write(struct IOSocket *iosocket, const char *line);
+void iosocket_send(struct IOSocket *iosocket, const char *data, size_t datalen);
+void iosocket_printf(struct IOSocket *iosocket, const char *text, ...);
+void iohandler_close(struct IOSocket *iosocket);
+
+#endif
diff --git a/src/IOHandler/IOTimer.c b/src/IOHandler/IOTimer.c
new file mode 100644 (file)
index 0000000..ec90d39
--- /dev/null
@@ -0,0 +1,201 @@
+/* IOTimer.c - IOMultiplexer v2
+ * Copyright (C) 2014  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+#define _IOHandler_internals
+#include "IOInternal.h"
+#include "IOHandler.h"
+#include "IOTimer.h"
+#include "IOLog.h"
+
+#include <sys/time.h>
+#include <stdlib.h>
+
+static void _rearrange_timer(struct _IOTimerDescriptor *timer);
+static void _autoreload_timer(struct _IOTimerDescriptor *timer);
+
+struct _IOTimerDescriptor *iotimer_sorted_descriptors;
+
+/* public functions */
+
+struct IOTimerDescriptor *iotimer_create(struct timeval *timeout) {
+       struct IOTimerDescriptor *descriptor = calloc(1, sizeof(*descriptor));
+    if(!descriptor) {
+        iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
+        return NULL;
+    }
+       struct _IOTimerDescriptor *timer = _create_timer(timeout);
+       if(!timer) {
+               free(descriptor);
+               return NULL;
+       }
+       timer->parent = descriptor;
+       timer->flags |= IOTIMERFLAG_PARENT_PUBLIC;
+       descriptor->iotimer = timer;
+       
+       return descriptor;
+}
+
+void iotimer_start(struct IOTimerDescriptor *descriptor) {
+       struct _IOTimerDescriptor *timer = descriptor->iotimer;
+       if(timer == NULL) {
+               iolog_trigger(IOLOG_WARNING, "called iotimer_set_autoreload for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
+               return;
+       }
+       timer->flags |= IOTIMERFLAG_ACTIVE;
+       if(!(timer->flags & IOTIMERFLAG_IN_LIST))
+               _trigger_timer(timer);
+}
+
+void iotimer_set_autoreload(struct IOTimerDescriptor *descriptor, struct timeval *autoreload) {
+       struct _IOTimerDescriptor *timer = descriptor->iotimer;
+       if(timer == NULL) {
+               iolog_trigger(IOLOG_WARNING, "called iotimer_set_autoreload for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
+               return;
+       }
+       if(autoreload) {
+               timer->flags |= IOTIMERFLAG_PERIODIC;
+               timer->autoreload = *autoreload;
+               
+               if(!(timer->flags & IOTIMERFLAG_IN_LIST)) {
+                       struct timeval now;
+                       gettimeofday(&now, NULL);
+                       timer->timeout = now;
+                       _autoreload_timer(timer);
+               }
+       } else {
+               timer->flags &= ~IOTIMERFLAG_PERIODIC;
+       }
+}
+
+void iotimer_set_callback(struct IOTimerDescriptor *descriptor, iotimer_callback *callback) {
+       descriptor->callback = callback;
+}
+
+void iotimer_destroy(struct IOTimerDescriptor *descriptor) {
+       struct _IOTimerDescriptor *timer = descriptor->iotimer;
+       if(timer == NULL) {
+               iolog_trigger(IOLOG_WARNING, "called iotimer_destroy for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
+               return;
+       }
+       descriptor->iotimer = NULL;
+       _destroy_timer(timer);
+       
+       iogc_add(descriptor);
+}
+
+/* internal functions */
+void _init_timers() {
+       //nothing in here
+}
+
+struct _IOTimerDescriptor *_create_timer(struct timeval *timeout) {
+       struct _IOTimerDescriptor *timer = calloc(1, sizeof(*timer));
+    if(!timer) {
+        iolog_trigger(IOLOG_ERROR, "could not allocate memory for _IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
+        return NULL;
+    }
+       if(timeout) {
+               timer->timeout = *timeout;
+               _rearrange_timer(timer);
+       }
+       return timer;
+}
+
+static void _rearrange_timer(struct _IOTimerDescriptor *timer) {
+       if((timer->flags & IOTIMERFLAG_IN_LIST)) {
+               if(timer->prev == NULL)
+                       iotimer_sorted_descriptors = timer->next;
+               else
+                       timer->prev->next = timer->next;
+               if(timer->next != NULL)
+                       timer->next->prev = timer->prev;
+       }
+       struct _IOTimerDescriptor *ctimer;
+       for(ctimer = iotimer_sorted_descriptors; ctimer; ctimer = ctimer->next) {
+               if(timeval_is_bigger(ctimer->timeout, timer->timeout)) {
+                       timer->next = ctimer;
+                       timer->prev = ctimer->prev;
+                       if(ctimer->prev)
+                               ctimer->prev->next = timer;
+                       else
+                               iotimer_sorted_descriptors = timer;
+                       ctimer->prev = timer;
+                       break;
+               }
+               else if(ctimer->next == NULL) {
+                       ctimer->next = timer;
+                       timer->prev = ctimer;
+                       break;
+               }
+       }
+       if(ctimer == NULL)
+               iotimer_sorted_descriptors = timer;
+       timer->flags |= IOTIMERFLAG_IN_LIST;
+}
+
+void _destroy_timer(struct _IOTimerDescriptor *timer) {
+       if((timer->flags & IOTIMERFLAG_IN_LIST)) {
+               if(timer->prev == NULL)
+                       iotimer_sorted_descriptors = timer->next;
+               else
+                       timer->prev->next = timer->next;
+               if(timer->next != NULL)
+                       timer->next->prev = timer->prev;
+       }
+       free(timer);
+}
+
+static void _autoreload_timer(struct _IOTimerDescriptor *timer) {
+       timer->timeout.tv_usec += timer->autoreload.tv_usec;
+       timer->timeout.tv_sec += timer->autoreload.tv_sec;
+       if(timer->timeout.tv_usec > 1000000) {
+               timer->timeout.tv_sec += (timer->timeout.tv_usec / 1000000);
+               timer->timeout.tv_usec %= 1000000;
+       }
+       _rearrange_timer(timer);
+}
+
+void _trigger_timer() {
+       struct timeval now;
+       _trigger_timer_start:
+       gettimeofday(&now, NULL);
+       
+       struct _IOTimerDescriptor *timer = iotimer_sorted_descriptors;
+       if(!timer || timeval_is_bigger(timer->timeout, now)) {
+               return;
+       }
+       iotimer_sorted_descriptors = timer->next;
+       if(timer->next != NULL)
+               timer->next->prev = timer->prev;
+       timer->flags &= ~IOTIMERFLAG_IN_LIST;
+       
+       if((timer->flags & IOTIMERFLAG_PERIODIC))
+               _autoreload_timer(timer);
+       
+       if(timer->flags & IOTIMERFLAG_PARENT_PUBLIC) {
+               struct IOTimerDescriptor *descriptor = timer->parent;
+               if(descriptor->callback)
+                       descriptor->callback(descriptor);
+               if(!(timer->flags & IOTIMERFLAG_PERIODIC))
+                       iotimer_destroy(descriptor);
+       } else {
+               if(!(timer->flags & IOTIMERFLAG_PERIODIC))
+                       _destroy_timer(timer);
+       }
+       
+       goto _trigger_timer_start;
+}
+
diff --git a/src/IOHandler/IOTimer.h b/src/IOHandler/IOTimer.h
new file mode 100644 (file)
index 0000000..c173282
--- /dev/null
@@ -0,0 +1,70 @@
+/* IOTimer.h - IOMultiplexer v2
+ * Copyright (C) 2014  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+#ifndef _IOTimer_h
+#define _IOTimer_h
+#ifndef _IOHandler_internals
+#include "IOHandler.h"
+#else
+#include <sys/time.h>
+
+
+#define IOTIMERFLAG_PERIODIC       0x01
+#define IOTIMERFLAG_ACTIVE         0x02
+#define IOTIMERFLAG_IN_LIST        0x04
+#define IOTIMERFLAG_PARENT_PUBLIC  0x08
+#define IOTIMERFLAG_PARENT_SOCKET  0x10
+
+struct _IOTimerDescriptor;
+
+extern struct _IOTimerDescriptor *iotimer_sorted_descriptors;
+
+struct _IOTimerDescriptor {
+    unsigned int flags : 8;
+    void *parent; 
+    
+    struct timeval timeout;
+    struct timeval autoreload;
+    
+    struct _IOTimerDescriptor *prev, *next;
+};
+
+void _init_timers();
+struct _IOTimerDescriptor *_create_timer(struct timeval *timeout);
+void _destroy_timer(struct _IOTimerDescriptor *timer);
+void _trigger_timer();
+
+#endif
+
+struct IOTimerDescriptor;
+
+#define IOTIMER_CALLBACK(NAME) void NAME(struct IOTimerDescriptor *iotimer)
+typedef IOTIMER_CALLBACK(iotimer_callback);
+
+struct IOTimerDescriptor {
+    void *iotimer; /* struct _IOTimerDescriptor */
+    
+    iotimer_callback *callback;
+    void *data;
+};
+
+struct IOTimerDescriptor *iotimer_create(struct timeval *timeout);
+void iotimer_start(struct IOTimerDescriptor *iotimer);
+void iotimer_set_autoreload(struct IOTimerDescriptor *iotimer, struct timeval *autoreload);
+void iotimer_set_callback(struct IOTimerDescriptor *iotimer, iotimer_callback *callback);
+void iotimer_destroy(struct IOTimerDescriptor *iotimer);
+
+#endif
diff --git a/src/IOHandler/Makefile.am b/src/IOHandler/Makefile.am
new file mode 100644 (file)
index 0000000..7cbb02c
--- /dev/null
@@ -0,0 +1,19 @@
+##Process this file with automake to create Makefile.in
+ACLOCAL_AMFLAGS = -I m4
+
+libiohandler_a_SOURCES = compat/utime.c \
+    compat/inet.c \
+    IOHandler.c \
+    IODNSEngine_cares.c \
+    IODNSEngine_default.c \
+    IODNSLookup.c \
+    IOEngine_epoll.c \
+    IOEngine_kevent.c \
+    IOEngine_select.c \
+    IOEngine_win32.c \
+    IOGarbageCollector.c \
+    IOLog.c \
+    IOSockets.c \
+    IOTimer.c
+
+noinst_LIBRARIES = libiohandler.a
diff --git a/src/IOHandler/compat/inet.c b/src/IOHandler/compat/inet.c
new file mode 100644 (file)
index 0000000..aa7245f
--- /dev/null
@@ -0,0 +1,86 @@
+/* inet.c - IOMultiplexer
+ * Copyright (C) 2014  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+#include "../IOHandler_config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+/* non-win32 systems have these functions defined... */
+#endif
+
+#ifndef HAVE_INET_PTON
+#ifdef WIN32
+int inet_pton(int af, const char *src, void *dst) {
+       struct sockaddr_storage ss;
+       int size = sizeof(ss);
+       char src_copy[INET6_ADDRSTRLEN+1];
+
+       memset(&ss, 0, sizeof(ss));
+       /* stupid non-const API */
+       strncpy (src_copy, src, INET6_ADDRSTRLEN+1);
+       src_copy[INET6_ADDRSTRLEN] = 0;
+
+       if(WSAStringToAddress(src_copy, af, NULL, (struct sockaddr *)&ss, &size) == 0) {
+               switch(af) {
+               case AF_INET:
+                       *(struct in_addr *)dst = ((struct sockaddr_in *)&ss)->sin_addr;
+                       return 1;
+               case AF_INET6:
+                       *(struct in6_addr *)dst = ((struct sockaddr_in6 *)&ss)->sin6_addr;
+                       return 1;
+               }
+       }
+       return 0;
+}
+#else
+
+
+#endif
+#endif
+
+#ifndef HAVE_INET_NTOP
+#ifdef WIN32
+const char *inet_ntop(int af, const void *src, char *dst, socklen_t size) {
+       struct sockaddr_storage ss;
+       unsigned long s = size;
+
+       memset(&ss, 0, sizeof(ss));
+       ss.ss_family = af;
+
+       switch(af) {
+       case AF_INET:
+               ((struct sockaddr_in *)&ss)->sin_addr = *(struct in_addr *)src;
+               break;
+       case AF_INET6:
+               ((struct sockaddr_in6 *)&ss)->sin6_addr = *(struct in6_addr *)src;
+               break;
+       default:
+               return NULL;
+       }
+       /* cannot direclty use &size because of strict aliasing rules */
+       return (WSAAddressToString((struct sockaddr *)&ss, sizeof(ss), NULL, dst, &s) == 0) ? dst : NULL;
+}
+#else
+
+
+#endif
+#endif
diff --git a/src/IOHandler/compat/inet.h b/src/IOHandler/compat/inet.h
new file mode 100644 (file)
index 0000000..a61424c
--- /dev/null
@@ -0,0 +1,37 @@
+/* inet.h - IOMultiplexer
+ * Copyright (C) 2014  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+#ifndef _compat_inet_h
+#define _compat_inet_h
+
+#ifndef HAVE_INET_PTON
+#ifdef WIN32
+int inet_pton(int af, const char *src, void *dst);
+#else
+
+#endif
+#endif
+
+#ifndef HAVE_INET_NTOP
+#ifdef WIN32
+#include <ws2tcpip.h>
+const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
+#else
+
+#endif
+#endif
+
+#endif
diff --git a/src/IOHandler/compat/utime.c b/src/IOHandler/compat/utime.c
new file mode 100644 (file)
index 0000000..193ab53
--- /dev/null
@@ -0,0 +1,84 @@
+/* utime.c - IOMultiplexer
+ * Copyright (C) 2014  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+#include "../IOHandler_config.h"
+#include "utime.h"
+#ifndef HAVE_USLEEP
+
+#ifdef HAVE_SELECT
+
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#else
+# include <sys/time.h>
+# include <sys/types.h>
+# include <unistd.h>
+#endif
+
+void usleep_tv(struct timeval tv) {
+       select(0, NULL, NULL, NULL, &tv);
+}
+
+void usleep(long usec)
+{
+       struct timeval tv;
+
+       tv.tv_sec = usec / 1000000;
+       tv.tv_usec = usec % 1000000;
+       usleep_tv(tv);
+}
+
+#elif defined WIN32
+
+/* usleep implementation from FreeSCI */
+
+#include <windows.h>
+
+void usleep_tv(struct timeval tv) {
+       usleep(tv.tv_sec * 1000000 + tv.tv_usec);
+}
+
+void usleep (long usec)
+{
+        LARGE_INTEGER lFrequency;
+        LARGE_INTEGER lEndTime;
+        LARGE_INTEGER lCurTime;
+
+        QueryPerformanceFrequency (&lFrequency);
+        if (lFrequency.QuadPart) {
+                QueryPerformanceCounter (&lEndTime);
+                lEndTime.QuadPart += (LONGLONG) usec *
+                                        lFrequency.QuadPart / 1000000;
+                do {
+                        QueryPerformanceCounter (&lCurTime);
+                        Sleep(0);
+                } while (lCurTime.QuadPart < lEndTime.QuadPart);
+        }
+}
+
+#endif
+
+#else
+#include <sys/time.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+void usleep_tv(struct timeval tv) {
+       usleep(tv.tv_sec * 1000000 + tv.tv_usec);
+}
+
+#endif /* !HAVE_USLEEP */
diff --git a/src/IOHandler/compat/utime.h b/src/IOHandler/compat/utime.h
new file mode 100644 (file)
index 0000000..4156880
--- /dev/null
@@ -0,0 +1,30 @@
+/* utime.h - IOMultiplexer
+ * Copyright (C) 2014  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+#ifndef _compat_utime_h
+#define _compat_utime_h
+#include "../IOHandler_config.h"
+#include <sys/time.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+void usleep_tv(struct timeval tv);
+
+#ifndef HAVE_USLEEP
+void usleep(long usec);
+#endif
+#endif
diff --git a/src/IOHandler_test/Makefile.am b/src/IOHandler_test/Makefile.am
new file mode 100644 (file)
index 0000000..5fc8fac
--- /dev/null
@@ -0,0 +1,3 @@
+##Process this file with automake to create Makefile.in
+ACLOCAL_AMFLAGS = -I m4
+SUBDIRS = socket timer
diff --git a/src/IOHandler_test/socket/.gitignore b/src/IOHandler_test/socket/.gitignore
new file mode 100644 (file)
index 0000000..d6a00c5
--- /dev/null
@@ -0,0 +1,3 @@
+.deps
+*.o
+iotest
diff --git a/src/IOHandler_test/socket/Makefile.am b/src/IOHandler_test/socket/Makefile.am
new file mode 100644 (file)
index 0000000..1dac3a5
--- /dev/null
@@ -0,0 +1,8 @@
+##Process this file with automake to create Makefile.in
+ACLOCAL_AMFLAGS = -I m4
+
+noinst_PROGRAMS = iotest
+iotest_LDADD = ../../IOHandler/libiohandler.a
+
+iotest_SOURCES = iotest.c
+
diff --git a/src/IOHandler_test/socket/iotest.c b/src/IOHandler_test/socket/iotest.c
new file mode 100644 (file)
index 0000000..ec9a330
--- /dev/null
@@ -0,0 +1,62 @@
+/* main.c - IOMultiplexer
+ * Copyright (C) 2012  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+
+#include <stdio.h>
+#include "../../IOHandler/IOHandler.h"
+#include "../../IOHandler/IOSockets.h"
+#include "../../IOHandler/IOLog.h"
+
+static IOSOCKET_CALLBACK(io_callback);
+static IOLOG_CALLBACK(io_log);
+
+static struct IOSocket *irc_iofd = NULL;
+
+int main(int argc, char *argv[]) {
+       iohandler_init();
+       
+    iolog_register_callback(io_log);
+    
+    irc_iofd = iosocket_connect_flags("irc.nextirc.net", 6667, 0, NULL, io_callback, IOSOCKET_ADDR_IPV4);
+    irc_iofd->parse_delimiter = 1;
+       irc_iofd->delimiters[0] = '\n';
+       irc_iofd->delimiters[1] = '\r';
+       
+       iohandler_run();
+       
+       return 0;
+}
+
+static IOSOCKET_CALLBACK(io_callback) {
+    switch(event->type) {
+        case IOSOCKETEVENT_CONNECTED:
+            printf("[connect]\n");
+            break;
+        case IOSOCKETEVENT_CLOSED:
+            printf("[disconnect]\n");
+            break;
+        case IOSOCKETEVENT_RECV:
+            printf("[in] %s\n", event->data.recv_str);
+            break;
+        
+        default:
+            break;
+    }
+}
+
+static IOLOG_CALLBACK(io_log) {
+    //printf("%s", line);
+}
diff --git a/src/IOHandler_test/timer/Makefile.am b/src/IOHandler_test/timer/Makefile.am
new file mode 100644 (file)
index 0000000..1dac3a5
--- /dev/null
@@ -0,0 +1,8 @@
+##Process this file with automake to create Makefile.in
+ACLOCAL_AMFLAGS = -I m4
+
+noinst_PROGRAMS = iotest
+iotest_LDADD = ../../IOHandler/libiohandler.a
+
+iotest_SOURCES = iotest.c
+
diff --git a/src/IOHandler_test/timer/iotest.c b/src/IOHandler_test/timer/iotest.c
new file mode 100644 (file)
index 0000000..97d43c6
--- /dev/null
@@ -0,0 +1,71 @@
+/* main.c - IOMultiplexer
+ * Copyright (C) 2012  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+
+#include <stdio.h>
+#include <sys/time.h>
+#include "../../IOHandler/IOHandler.h"
+#include "../../IOHandler/IOTimer.h"
+#include "../../IOHandler/IOLog.h"
+
+#define TEST_DURATION 100
+
+static IOTIMER_CALLBACK(io_callback);
+static IOLOG_CALLBACK(io_log);
+
+static struct timeval test_clock1, test_clock2;
+static int timercount;
+
+int main(int argc, char *argv[]) {
+       iohandler_init();
+       iolog_register_callback(io_log);
+       
+       gettimeofday(&test_clock1, NULL);
+       gettimeofday(&test_clock2, NULL);
+
+       struct timeval tv;
+       tv.tv_sec = TEST_DURATION / 1000;
+       tv.tv_usec = TEST_DURATION % 1000 * 1000;
+       struct IOTimerDescriptor *timer = iotimer_create(NULL);
+       iotimer_set_callback(timer, io_callback);
+       iotimer_set_autoreload(timer, &tv);
+       iotimer_start(timer);
+       
+       timercount = 0;
+       
+       printf("[timer 0] %ld.%ld\n", test_clock1.tv_sec, test_clock1.tv_usec);
+       
+       iohandler_run();
+       return 1;
+}
+
+static IOTIMER_CALLBACK(io_callback) {
+       struct timeval curr_time;
+       int diff1;
+       double diff2;
+       
+       timercount++;
+       gettimeofday(&curr_time, NULL);
+       diff1 = (curr_time.tv_sec - test_clock1.tv_sec) * 1000 + ((curr_time.tv_usec - test_clock1.tv_usec) / 1000);
+       diff2 = (curr_time.tv_sec - test_clock2.tv_sec) * 1000 + ((curr_time.tv_usec - test_clock2.tv_usec) / 1000.0);
+       diff2 -= (timercount * TEST_DURATION);
+       gettimeofday(&test_clock1, NULL);
+       printf("[timer %03d] %ld.%06ld [%d ms]  accuracy: %f ms\n", timercount, curr_time.tv_sec, curr_time.tv_usec, diff1, diff2);
+}
+
+static IOLOG_CALLBACK(io_log) {
+       //printf("%s", line);
+}
diff --git a/src/IOInternal.h b/src/IOInternal.h
deleted file mode 100644 (file)
index 2dd5950..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/* IOInternal.h - IOMultiplexer v2
- * Copyright (C) 2014  Philipp Kreil (pk910)
- * 
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License 
- * along with this program. If not, see <http://www.gnu.org/licenses/>. 
- */
-#ifndef _IOInternal_h
-#define _IOInternal_h
-#ifndef _IOHandler_internals
-#include "IOHandler.h"
-#else
-
-/* Multithreading */
-#ifdef HAVE_PTHREAD_H
-#include <pthread.h>
-#ifdef PTHREAD_MUTEX_RECURSIVE_NP
-#define PTHREAD_MUTEX_RECURSIVE_VAL PTHREAD_MUTEX_RECURSIVE_NP
-#else
-#define PTHREAD_MUTEX_RECURSIVE_VAL PTHREAD_MUTEX_RECURSIVE
-#endif
-#define IOTHREAD_MUTEX_INIT(var) { \
-    pthread_mutexattr_t mutex_attr; \
-    pthread_mutexattr_init(&mutex_attr);\
-    pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE_VAL);\
-    pthread_mutex_init(&var, &mutex_attr); \
-}
-#define IOSYNCHRONIZE(var) pthread_mutex_lock(&var)
-#define IODESYNCHRONIZE(var) pthread_mutex_unlock(&var)
-#else
-#define IOTHREAD_MUTEX_INIT(var)
-#define IOSYNCHRONIZE(var)
-#define IODESYNCHRONIZE(var)
-#endif
-
-
-#define IOGC_FREE(NAME) void NAME(void *object)
-typedef IOGC_FREE(iogc_free);
-void iogc_add(void *object);
-void iogc_add_callback(void *object, iogc_free *free_callback);
-
-#endif
-#endif
diff --git a/src/IOLog.c b/src/IOLog.c
deleted file mode 100644 (file)
index 04af476..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/* IOLog.c - IOMultiplexer v2
- * Copyright (C) 2014  Philipp Kreil (pk910)
- * 
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License 
- * along with this program. If not, see <http://www.gnu.org/licenses/>. 
- */
-#define _IOHandler_internals
-#include "IOInternal.h"
-#include "IOHandler.h"
-#include "IOLog.h"
-
-void iolog_init() {
-
-}
-
-void iolog_trigger(enum IOLogType type, char *text, ...) {
-    va_list arg_list;
-    char logBuf[MAXLOG+1];
-    int pos;
-    logBuf[0] = '\0';
-    va_start(arg_list, text);
-    pos = vsnprintf(logBuf, MAXLOG - 1, text, arg_list);
-    va_end(arg_list);
-    if (pos < 0 || pos > (MAXLOG - 1)) pos = MAXLOG - 1;
-    logBuf[pos] = '\n';
-    logBuf[pos+1] = '\0';
-    
-    
-}
diff --git a/src/IOLog.h b/src/IOLog.h
deleted file mode 100644 (file)
index 0296b3d..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/* IOLog.h - IOMultiplexer v2
- * Copyright (C) 2014  Philipp Kreil (pk910)
- * 
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License 
- * along with this program. If not, see <http://www.gnu.org/licenses/>. 
- */
-#ifndef _IOInternal_h
-#define _IOInternal_h
-#ifndef _IOHandler_internals
-#include "IOHandler.h"
-#else
-enum IOLogType;
-
-void iolog_init();
-void iolog_trigger(enum IOLogType type, char *text, ...);
-
-#endif
-
-enum IOLogType {
-    IOLOG_DEBUG,
-    IOLOG_WARNING,
-    IOLOG_ERROR,
-    IOLOG_FATAL
-};
-
-/* TODO: Functions to get messages from IOLog */
-
-#endif
diff --git a/src/IOSockets.c b/src/IOSockets.c
deleted file mode 100644 (file)
index 7e912f0..0000000
+++ /dev/null
@@ -1,748 +0,0 @@
-/* IOSockets.c - IOMultiplexer v2
- * Copyright (C) 2014  Philipp Kreil (pk910)
- * 
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License 
- * along with this program. If not, see <http://www.gnu.org/licenses/>. 
- */
-#define _IOHandler_internals
-#include "IOInternal.h"
-#include "IOHandler.h"
-#include "IOSockets.h"
-#include "IOLog.h"
-#include "IODNSLookup.h"
-
-#ifdef HAVE_PTHREAD_H
-static pthread_mutex_t iosocket_sync, iosocket_dns_sync;
-#endif
-
-static struct _IOSocket *iosocket_first = NULL;
-static struct _IOSocket *iosocket_last = NULL;
-
-/* IO Engines */
-extern struct IOEngine engine_select; /* select system call (should always be useable) */
-extern struct IOEngine engine_kevent;
-extern struct IOEngine engine_epoll;
-extern struct IOEngine engine_win32;
-
-struct IOEngine *engine = NULL;
-
-
-static void iosocket_increase_buffer(struct IOSocketBuffer *iobuf, size_t required);
-static int iosocket_parse_address(const char *hostname, struct IODNSAddress *addr, int records);
-static int iosocket_lookup_hostname(struct _IOSocket *iosock, const char *hostname, int records, int bindaddr);
-static void iosocket_lookup_apply(struct _IOSocket *iosock, struct IODNSAddress *addr, int bindlookup);
-static void iosocket_connect_finish(struct _IOSocket *iosock);
-static void iosocket_listen_finish(struct _IOSocket *iosock);
-
-
-
-
-static void iosockets_init_engine() {
-    //try other engines
-       if(!engine && engine_kevent.init && engine_kevent.init())
-               engine = &engine_kevent;
-       if(!engine && engine_epoll.init && engine_epoll.init())
-               engine = &engine_epoll;
-       if(!engine && engine_win32.init && engine_win32.init())
-               engine = &engine_win32;
-    
-    if (!engine) {
-        if(engine_select.init())
-            engine = &engine_select;
-        else {
-            iolog_trigger(IOLOG_FATAL, "found no useable IO engine");
-            return;
-        }
-    }
-    iolog_trigger(IOLOG_DEBUG, "using %s IOSockets engine", engine->name);
-}
-
-void _init_sockets() {
-       IOTHREAD_MUTEX_INIT(iosocket_sync);
-       IOTHREAD_MUTEX_INIT(iosocket_dns_sync);
-       iosockets_init_engine();
-}
-
-
-struct _IOSocket _create_socket() {
-       struct _IOSocket *iosock = calloc(1, sizeof(*iosock));
-       if(!iosock) {
-               iolog_trigger(IOLOG_ERROR, "could not allocate memory for _IOSocket in %s:%d", __FILE__, __LINE__);
-               return NULL;
-       }
-       IOSYNCHRONIZE(iosocket_sync);
-       if(iosocket_last)
-               iosocket_last->next = iosock;
-       else
-               iosocket_first = iosock;
-       iosock->prev = iosocket_last;
-       iosocket_last = iosock;
-       IODESYNCHRONIZE(iosocket_sync);
-       return iosock;
-}
-
-void _free_socket(struct _IOSocket *iosock) {
-       iosocket_deactivate(iosock);
-       IOSYNCHRONIZE(iosocket_sync);
-       if(iosock->prev)
-               iosock->prev->next = iosock->next;
-       else
-               iosocket_first = iosock->next;
-       if(iosock->next)
-               iosock->next->prev = iosock->prev;
-       else
-               iosocket_last = iosock->prev;
-       IODESYNCHRONIZE(iosocket_sync);
-       
-       if(iosock->bind.addr.addresslen)
-               free(iosock->bind.addr.address);
-       if(iosock->dest.addr.addresslen)
-               free(iosock->dest.addr.address);
-       if(iosock->readbuf.buffer)
-               free(iosock->readbuf.buffer);
-       if(iosock->writebuf.buffer)
-               free(iosock->writebuf.buffer);
-       
-       free(iosock);
-}
-
-static void iosocket_activate(struct _IOSocket *iosock) {
-       if((iosock->flags & IOSOCKETFLAG_ACTIVE))
-               return;
-       iosock->flags |= IOSOCKETFLAG_ACTIVE;
-       engine->add(iosock);
-}
-
-static void iosocket_deactivate(struct _IOSocket *iosock) {
-       if(!(iosock->flags & IOSOCKETFLAG_ACTIVE))
-               return;
-       iosock->flags &= ~IOSOCKETFLAG_ACTIVE;
-       engine->remove(iosock);
-}
-
-static void iosocket_increase_buffer(struct IOSocketBuffer *iobuf, size_t required) {
-    if(iobuf->buflen >= required) return;
-    char *new_buf = realloc(iobuf->buffer, required + 2);
-    if(new_buf) {
-        iobuf->buffer = new_buf;
-        iobuf->buflen = required;
-    }
-}
-
-static int iosocket_parse_address(const char *hostname, struct IODNSAddress *addr, int records) {
-       int ret;
-       if((flags & IOSOCKET_ADDR_IPV4)) {
-               struct sockaddr_in ip4addr;
-               ret = inet_pton(AF_INET, hostname, &(ip4addr.sin_addr));
-               if(ret == 1) {
-                       addr->addresslen = sizeof(*ip4addr);
-                       addr->address = malloc(addr->addresslen);
-                       if(!addr->address) {
-                               iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__);
-                               return -1;
-                       }
-                       memcpy(addr->address, ip4addr, addr->addresslen);
-                       return 1;
-               }
-       }
-       if((flags & IOSOCKET_ADDR_IPV6)) {
-               struct sockaddr_in6 ip6addr;
-               ret = inet_pton(AF_INET6, hostname, &(ip6addr.sin6_addr));
-               if(ret == 1) {
-                       addr->addresslen = sizeof(*ip6addr);
-                       addr->address = malloc(addr->addresslen);
-                       if(!addr->address) {
-                               iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__);
-                               return -1;
-                       }
-                       memcpy(addr->address, ip6addr, addr->addresslen);
-                       return 1;
-               }
-       }
-       return 0;
-}
-
-static int iosocket_lookup_hostname(struct _IOSocket *iosock, const char *hostname, int records, int bindaddr) {
-       struct IOSocketDNSLookup *lookup = calloc(1, sizeof(*lookup));
-       if(!lookup) {
-               iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOSocketDNSLookup in %s:%d", __FILE__, __LINE__);
-               return 0;
-       }
-       
-       struct _IODNSQuery *query = _create_dnsquery();
-       if(!query) {
-               free(lookup);
-               return 0;
-       }
-       
-       query->parent = lookup;
-       query->flags |= IODNSFLAG_PARENT_SOCKET;
-       lookup->iosocket = iosocket;
-       lookup->query = query;
-       strncpy(lookup->hostname, hostname, sizeof(lookup->hostname));
-       lookup->hostname[sizeof(lookup->hostname)-1] = 0;
-       if(bindaddr) {
-               lookup->bindlookup = 1;
-               iosock->bind.addrlookup = lookup;
-       } else {
-               lookup->bindlookup = 0;
-               iosock->dest.addrlookup = lookup;
-       }
-       
-       int dnsrecords = 0;
-       if((records & IOSOCKET_ADDR_IPV4))
-               dnsrecords |= IODNS_RECORD_A;
-       if((records & IOSOCKET_ADDR_IPV6))
-               dnsrecords |= IODNS_RECORD_AAAA;
-       
-       query->request.host = strdup(hostname);
-       query->type = (dnsrecords & IODNS_FORWARD);
-       
-       _start_dnsquery(query);
-       return 1;
-}
-
-void iosocket_lookup_callback(struct IOSocketDNSLookup *lookup, struct IODNSEvent *event) {
-       lookup->query = NULL;
-       IOSYNCHRONIZE(iosocket_dns_sync);
-       struct _IOSocket *iosock = lookup->iosock;
-       if(iosock == NULL) {
-               IODESYNCHRONIZE(iosocket_dns_sync);
-               return;
-       }
-       if(event->type == IODNSEVENT_SUCCESS)
-               lookup->result = event->result;
-       else
-               lookup->result = NULL;
-       
-       if(lookup->bindlookup) {
-               iosock->flags &= ~IOSOCKETFLAG_PENDING_BINDDNS;
-               iosock->flags |= IOSOCKETFLAG_DNSDONE_BINDDNS;
-       } else {
-               iosock->flags &= ~IOSOCKETFLAG_PENDING_DESTDNS;
-               iosock->flags |= IOSOCKETFLAG_DNSDONE_DESTDNS;
-       }
-       
-       int dns_finished = 0;
-       if((iosock->flags & (IOSOCKETFLAG_PENDING_BINDDNS | IOSOCKETFLAG_PENDING_DESTDNS)) == 0)
-               dns_finished = 1;
-       IODESYNCHRONIZE(iosocket_dns_sync);
-       if(dns_finished) {
-               int ret;
-               ret = iosocket_lookup_apply(iosock);
-               if(ret) { //if ret=0 an error occured in iosocket_lookup_apply and we should stop here.
-                       if((iosock->flags & IOSOCKETFLAG_LISTENING))
-                               iosocket_listen_finish(iosock);
-                       else
-                               iosocket_connect_finish(iosock);
-               }
-       }
-}
-
-static void iosocket_lookup_apply(struct _IOSocket *iosock) {
-       char errbuf[512];
-       struct IOSocketDNSLookup *bind_lookup = ((iosock->flags & IOSOCKETFLAG_DNSDONE_BINDDNS) ? iosock->bind.addrlookup : NULL);
-       struct IOSocketDNSLookup *dest_lookup = ((iosock->flags & IOSOCKETFLAG_DNSDONE_DESTDNS) ? iosock->dest.addrlookup : NULL);
-       if(!bind_lookup && !dest_lookup) {
-               iosock->flags |= IOSOCKETFLAG_DNSERROR;
-               sprintf(errbuf, "Internal Error");
-               iolog_trigger(IOLOG_ERROR, "trying to apply lookup results without any lookups processed in %s:%d", __FILE__, __LINE__);
-               goto iosocket_lookup_clear;
-       }
-       
-       struct IODNSResult *result;
-       int bind_numip4 = 0, bind_numip6 = 0;
-       int dest_numip4 = 0, dest_numip6 = 0;
-       
-       if(bind_lookup) {
-               for(result = bind_lookup->result; result; result = result->next) {
-                       if((result->type & IODNS_RECORD_A))
-                               bind_numip4++;
-                       if((result->type & IODNS_RECORD_AAAA))
-                               bind_numip6++;
-               }
-       }
-       if(dest_lookup) {
-               for(result = dest_lookup->result; result; result = result->next) {
-                       if((result->type & IODNS_RECORD_A))
-                               dest_numip4++;
-                       if((result->type & IODNS_RECORD_AAAA))
-                               dest_numip6++;
-               }
-       }
-       int useip6 = 0;
-       int useip4 = 0;
-       if(bind_lookup && (bind_numip6 == 0 && bind_numip4 == 0)) {
-               iosock->flags |= IOSOCKETFLAG_DNSERROR;
-               sprintf(errbuf, "could not lookup bind address (%s)", bind_lookup->hostname);
-               goto iosocket_lookup_clear;
-       } else if(dest_lookup && (dest_numip6 == 0 && dest_numip4 == 0)) {
-               iosock->flags |= IOSOCKETFLAG_DNSERROR;
-               sprintf(errbuf, "could not lookup destination address (%s)", dest_lookup->hostname);
-               goto iosocket_lookup_clear;
-       } else if(bind_lookup && dest_lookup) {
-               if(bind_numip6 > 0 && dest_numip6 > 0)
-                       useip6 = 1;
-               else if(bind_numip4 > 0 && dest_numip4 > 0)
-                       useip4 = 1;
-               else {
-                       iosock->flags |= IOSOCKETFLAG_DNSERROR;
-                       sprintf(errbuf, "could not lookup adresses of the same IP family for bind and destination host. (bind: %d ip4, %d ip6 | dest: %d ip4, %d ip6)", bind_numip4, bind_numip6, dest_numip4, dest_numip6);
-                       goto iosocket_lookup_clear;
-               }
-       } else if(bind_lookup) {
-               if(bind_numip6)
-                       useip6 = 1;
-               else if(bind_numip4)
-                       useip4 = 1;
-       } else if(dest_lookup) {
-               if(dest_numip6)
-                       useip6 = 1;
-               else if(dest_numip4)
-                       useip4 = 1;
-       }
-       
-       int usetype = 0;
-       if(useip6) {
-               usetype = IODNS_RECORD_AAAA;
-               iosock->flags |= IOSOCKETFLAG_IPV6SOCKET;
-       } else {
-               usetype = IODNS_RECORD_A;
-       }
-       
-       #define IOSOCKET_APPLY_COPYADDR(type) \
-       iosock->type.addr.addresslen = result->result.addr.addresslen; \
-       iosock->type.addr.address = malloc(result->result.addr.addresslen); \
-       if(!iosock->type.addr.address) { \
-               iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__); \
-               iosock->type.addr.addresslen = 0; \
-               iosock->flags |= IOSOCKETFLAG_DNSERROR; \
-               sprintf(errbuf, "could not allocate memory for dns information"); \
-               goto iosocket_lookup_clear; \
-       } \
-       memcpy(iosock->type.addr.address, result->result.addr.address, result->result.addr.addresslen);
-       
-       
-       if(bind_lookup) {
-               int usenum = (useip6 ? bind_numip6 : bind_numip4);
-               usenum = rand() % usenum;
-               for(result = bind_lookup->result; result; result = result->next) {
-                       if((result->type & usetype)) {
-                               if(usenum == 0) {
-                                       IOSOCKET_APPLY_COPYADDR(bind)
-                                       break;
-                               }
-                               usenum--;
-                       }
-               }
-       } else
-               iosock->bind.addr.addresslen = 0;
-       
-       if(dest_lookup) {
-               int usenum = (useip6 ? dest_numip6 : dest_numip4);
-               usenum = rand() % usenum;
-               for(result = dest_lookup->result; result; result = result->next) {
-                       if((result->type & usetype)) {
-                               if(usenum == 0) {
-                                       IOSOCKET_APPLY_COPYADDR(dest)
-                                       break;
-                               }
-                               usenum--;
-                       }
-               }
-       } else
-               iosock->dest.addr.addresslen = 0;
-       
-       iosocket_lookup_clear:
-       if(bind_lookup) {
-               if(bind_lookup->result)
-                       iodns_free_result(bind_lookup->result);
-               free(bind_lookup);
-       }
-       if(dest_lookup) {
-               if(bind_lookup->result)
-                       iodns_free_result(dest_lookup->result);
-               free(dest_lookup);
-       }
-       
-       if((iosock->flags & IOSOCKETFLAG_DNSERROR)) {
-               // TODO: trigger error
-               
-               return 0;
-       } else
-               return 1;
-}
-
-static void iosocket_connect_finish(struct _IOSocket *iosock) {
-       int sockfd;
-       if((iosock->flags & IOSOCKETFLAG_IPV6SOCKET))
-               sockfd = socket(AF_INET6, SOCK_STREAM, 0);
-       else
-               sockfd = socket(AF_INET, SOCK_STREAM, 0);
-       if(sockfd == -1) {
-               iolog_trigger(IOLOG_ERROR, "could not create socket in %s:%d", __FILE__, __LINE__);
-               // TODO: trigger error
-               
-               return;
-       }
-       
-       // set port and bind address
-       if((iosock->flags & IOSOCKETFLAG_IPV6SOCKET)) {
-               struct sockaddr_in6 *ip6 = iosock->dest.addr.address;
-               ip6->sin6_family = AF_INET6;
-        ip6->sin6_port = htons(iosock->port);
-               
-               if(iosock->bind.addr.addresslen) {
-                       struct sockaddr_in6 *ip6bind = iosock->bind.addr.address;
-                       ip6bind->sin6_family = AF_INET6;
-                       ip6bind->sin6_port = htons(0);
-                       
-                       bind(sockfd, (struct sockaddr*)ip6bind, sizeof(*ip6bind));
-               }
-       } else {
-               struct sockaddr_in *ip4 = iosock->dest.addr.address;
-               ip->sin_family = AF_INET;
-        ip->sin_port = htons(iosock->port);
-               
-               if(iosock->bind.addr.addresslen) {
-                       struct sockaddr_in *ip4bind = iosock->bind.addr.address;
-                       ip4bind->sin_family = AF_INET;
-                       ip4bind->sin6_port = htons(0);
-                       
-                       bind(sockfd, (struct sockaddr*)ip4bind, sizeof(*ip4bind));
-               }
-       }
-       
-       // prevent SIGPIPE
-    #ifndef WIN32
-    #if defined(SO_NOSIGPIPE)
-    {
-        int set = 1;
-        setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
-    }
-    #else
-    signal(SIGPIPE, SIG_IGN);
-    #endif
-    #endif
-       
-    // make sockfd unblocking
-    #if defined(F_GETFL)
-    {
-        int fcntl_flags;
-        fcntl_flags = fcntl(sockfd, F_GETFL);
-        fcntl(sockfd, F_SETFL, fcntl_flags|O_NONBLOCK);
-        fcntl_flags = fcntl(sockfd, F_GETFD);
-        fcntl(sockfd, F_SETFD, fcntl_flags|FD_CLOEXEC);
-    }
-    #else
-    /* I hope you're using the Win32 backend or something else that
-     * automatically marks the file descriptor non-blocking...
-     */
-    #endif
-       
-       connect(sockfd, iosock->dest.addr.address, iosock->dest.addr.addresslen); //returns EINPROGRESS here (nonblocking)
-       iosock->fd = sockfd;
-       
-       iosocket_activate(iosock);
-}
-
-static void iosocket_listen_finish(struct _IOSocket *iosock) {
-       int sockfd;
-       if((iosock->flags & IOSOCKETFLAG_IPV6SOCKET))
-               sockfd = socket(AF_INET6, SOCK_STREAM, 0);
-       else
-               sockfd = socket(AF_INET, SOCK_STREAM, 0);
-       if(sockfd == -1) {
-               iolog_trigger(IOLOG_ERROR, "could not create socket in %s:%d", __FILE__, __LINE__);
-               // TODO: trigger error
-               
-               return;
-       }
-       
-       // set port and bind address
-       if((iosock->flags & IOSOCKETFLAG_IPV6SOCKET)) {
-               struct sockaddr_in6 *ip6bind = iosock->bind.addr.address;
-               ip6bind->sin6_family = AF_INET6;
-               ip6bind->sin6_port = htons(0);
-               
-               int opt = 1;
-        setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt));
-               
-               bind(sockfd, (struct sockaddr*)ip6bind, sizeof(*ip6bind));
-       } else {
-               struct sockaddr_in *ip4bind = iosock->bind.addr.address;
-               ip4bind->sin_family = AF_INET;
-               ip4bind->sin6_port = htons(0);
-               
-               int opt = 1;
-        setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt));
-               
-               bind(sockfd, (struct sockaddr*)ip4bind, sizeof(*ip4bind));
-       }
-       
-       // prevent SIGPIPE
-    #ifndef WIN32
-    #if defined(SO_NOSIGPIPE)
-    {
-        int set = 1;
-        setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
-    }
-    #else
-    signal(SIGPIPE, SIG_IGN);
-    #endif
-    #endif
-       
-    // make sockfd unblocking
-    #if defined(F_GETFL)
-    {
-        int fcntl_flags;
-        fcntl_flags = fcntl(sockfd, F_GETFL);
-        fcntl(sockfd, F_SETFL, fcntl_flags|O_NONBLOCK);
-        fcntl_flags = fcntl(sockfd, F_GETFD);
-        fcntl(sockfd, F_SETFD, fcntl_flags|FD_CLOEXEC);
-    }
-    #else
-    /* I hope you're using the Win32 backend or something else that
-     * automatically marks the file descriptor non-blocking...
-     */
-    #endif
-       
-       listen(sockfd, 1);
-       iosock->fd = sockfd;
-       
-       iosocket_activate(iosock);
-}
-
-/* public functions */
-
-struct IOSocket *iosocket_connect(const char *hostname, unsigned int port, int ssl, const char *bindhost, iosocket_callback *callback) {
-       return iosocket_connect_flags(hostname, port, ssl, bindhost, callback, (IOSOCKET_ADDR_IPV4 | IOSOCKET_ADDR_IPV6));
-}
-
-struct IOSocket *iosocket_connect_flags(const char *hostname, unsigned int port, int ssl, const char *bindhost, iosocket_callback *callback, int flags) {
-       struct IOSocket *iodescriptor = calloc(1, sizeof(*iodescriptor));
-       if(!iodescriptor) {
-               iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOSocket in %s:%d", __FILE__, __LINE__);
-               return NULL;
-       }
-       
-       struct _IOSocket *iosock = _create_socket();
-       if(!iosock) {
-               free(iodescriptor);
-               return NULL;
-       }
-       
-       iodescriptor->iosocket = iosock;
-       iodescriptor->status = IOSOCKET_CONNECTING;
-       iodescriptor->callback = callback;
-       iosock->parent = iodescriptor;
-       iosock->flags |= IOSOCKETFLAG_PARENT_PUBLIC;
-       if(ssl)
-               iosock->flags |= IOSOCKETFLAG_SSLSOCKET;
-       
-       IOSYNCHRONIZE(iosocket_dns_sync);
-       if(bindhost) {
-               switch(iosocket_parse_address(bindhost, &iosock->bind.addr, flags)) {
-               case -1:
-                       free(iosock);
-                       return NULL;
-               case 0:
-                       /* start dns lookup */
-                       iosock->flags |= IOSOCKETFLAG_PENDING_BINDDNS;
-                       iosocket_lookup_hostname(iosock, bindhost, flags, 1);
-                       break;
-               case 1:
-                       /* valid address */
-                       break;
-               }
-       }
-       switch(iosocket_parse_address(hostname, &iosock->dest.addr, flags)) {
-       case -1:
-               free(iosock);
-               return NULL;
-       case 0:
-               /* start dns lookup */
-               iosock->flags |= IOSOCKETFLAG_PENDING_DESTDNS;
-               iosocket_lookup_hostname(iosock, hostname, flags, 0);
-               break;
-       case 1:
-               /* valid address */
-               break;
-       }
-       IODESYNCHRONIZE(iosocket_dns_sync);
-       if((iosock->flags & (IOSOCKETFLAG_PENDING_BINDDNS | IOSOCKETFLAG_PENDING_DESTDNS)) == 0) {
-               iosocket_connect_finish(iosock);
-       }
-       return iodescriptor;
-}
-
-struct IOSocket *iosocket_listen(const char *hostname, unsigned int port, iosocket_callback *callback) {
-       return iosocket_listen_flags(hostname, port, callback, (IOSOCKET_ADDR_IPV4 | IOSOCKET_ADDR_IPV6));
-}
-
-struct IOSocket *iosocket_listen_flags(const char *hostname, unsigned int port, iosocket_callback *callback, int flags) {
-       struct IOSocket *iodescriptor = calloc(1, sizeof(*iodescriptor));
-       if(!iodescriptor) {
-               iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOSocket in %s:%d", __FILE__, __LINE__);
-               return NULL;
-       }
-       
-       struct _IOSocket *iosock = _create_socket();
-       if(!iosock) {
-               free(iodescriptor);
-               return NULL;
-       }
-       
-       iodescriptor->iosocket = iosock;
-       iodescriptor->status = IOSOCKET_CONNECTING;
-       iodescriptor->callback = callback;
-       iosock->parent = iodescriptor;
-       iosock->flags |= IOSOCKETFLAG_PARENT_PUBLIC | IOSOCKETFLAG_LISTENING;
-       if(ssl)
-               iosock->flags |= IOSOCKETFLAG_SSLSOCKET;
-       
-       IOSYNCHRONIZE(iosocket_dns_sync);
-       switch(iosocket_parse_address(hostname, &iosock->bind.addr, flags)) {
-       case -1:
-               free(iosock);
-               return NULL;
-       case 0:
-               /* start dns lookup */
-               iosock->flags |= IOSOCKETFLAG_PENDING_BINDDNS;
-               iosocket_lookup_hostname(iosock, hostname, flags, 1);
-               break;
-       case 1:
-               /* valid address */
-               break;
-       }
-       IODESYNCHRONIZE(iosocket_dns_sync);
-       if((iosock->flags & IOSOCKETFLAG_PENDING_BINDDNS) == 0) {
-               iosocket_listen_finish(iosock);
-       }
-       return iodescriptor;
-}
-
-struct IOSocket *iosocket_listen_ssl(const char *hostname, unsigned int port, const char *certfile, const char *keyfile, iosocket_callback *callback) {
-       return iosocket_listen_ssl_flags(hostname, port, certfile, keyfile, callback, (IOSOCKET_ADDR_IPV4 | IOSOCKET_ADDR_IPV6));
-}
-
-struct IOSocket *iosocket_listen_ssl_flags(const char *hostname, unsigned int port, const char *certfile, const char *keyfile, iosocket_callback *callback, int flags) {
-       //TODO: SSL
-       return NULL;
-}
-
-void iosocket_close(struct IOSocket *iosocket) {
-       struct _IOSocket *iosock = iosocket->iosocket;
-       if(iosock == NULL) {
-               iolog_trigger(IOLOG_WARNING, "called iosocket_close for destroyed IOSocket in %s:%d", __FILE__, __LINE__);
-               return NULL;
-       }
-       
-       iosock->flags |= IOSOCKETFLAG_SHUTDOWN;
-       
-       if(iosock->writebuf.bufpos) {
-        //try to send everything before closing
-#if defined(F_GETFL)
-        {
-            int flags;
-            flags = fcntl(iosock->fd, F_GETFL);
-            fcntl(iosock->fd, F_SETFL, flags & ~O_NONBLOCK);
-            flags = fcntl(iosock->fd, F_GETFD);
-            fcntl(iosock->fd, F_SETFD, flags|FD_CLOEXEC);
-        }
-#else
-        iosocket_deactivate(iosock);
-#endif
-        iosocket_try_write(iosock);
-    }
-       //close IOSocket
-    if(iosock->sslnode) {
-               //TODO: SSL
-       }
-       close(iosock->fd);
-    _free_socket(iosock);
-       iosocket->iosocket = NULL;
-       iosocket->status = IOSOCKET_CLOSED;
-       iogc_add(iosocket);
-}
-
-static int iohandler_try_write(struct _IOSocket *iosock) {
-    if(!iosock->writebuf.bufpos) return 0;
-    iolog_trigger(IOLOG_DEBUG, "write writebuf (%d bytes) to socket (fd: %d)", iosock->writebuf.bufpos, iosock->fd);
-    int res;
-    if(iosock->sslnode) {
-        /* res = iohandler_ssl_write(iofd, iofd->writebuf.buffer, iofd->writebuf.bufpos); */
-               // TODO
-    } else
-        res = send(iosock->fd, iosock->writebuf.buffer, iosock->writebuf.bufpos, 0);
-    if(res < 0) {
-        if (errno != EAGAIN && errno != EWOULDBLOCK)
-            iolog_trigger(IOLOG_ERROR, "could not write to socket (fd: %d): %d - %s", iosock->fd, errno, strerror(errno));
-        else
-            res = 0;
-    } else {
-        iosock->writebuf.bufpos -= res;
-               if((iosock->flags & (IOSOCKETFLAG_ACTIVE & IOSOCKETFLAG_SHUTDOWN)) == IOSOCKETFLAG_ACTIVE)
-                       engine->update(iosock);
-    }
-    return res;
-}
-
-void iosocket_send(struct IOSocket *iosocket, const char *data, size_t datalen) {
-       struct _IOSocket *iosock = iosocket->iosocket;
-       if(iosock == NULL) {
-               iolog_trigger(IOLOG_WARNING, "called iosocket_close for destroyed IOSocket in %s:%d", __FILE__, __LINE__);
-               return;
-       }
-       if(iosock->flags & IOSOCKETFLAG_SHUTDOWN) {
-        iolog_trigger(IOLOG_ERROR, "could not write to socket (socket is closing)");
-        return;
-    }
-    iolog_trigger(IOLOG_DEBUG, "add %d to writebuf (fd: %d): %s", datalen, iosock->fd, data);
-    if(iosock->writebuf.buflen < iosock->writebuf.bufpos + datalen) {
-        iolog_trigger(IOLOG_DEBUG, "increase writebuf (curr: %d) to %d (+%d bytes)", iosock->writebuf.buflen, iosock->writebuf.bufpos + datalen, (iosock->writebuf.bufpos + datalen - iosock->writebuf.buflen));
-        iosocket_increase_buffer(&iosock->writebuf, iosock->writebuf.bufpos + datalen);
-        if(iosock->writebuf.buflen < iosock->writebuf.bufpos + datalen) {
-            iolog_trigger(IOLOG_ERROR, "increase writebuf (curr: %d) to %d (+%d bytes) FAILED", iosock->writebuf.buflen, iosock->writebuf.bufpos + datalen, (iosock->writebuf.bufpos + datalen - iosock->writebuf.buflen));
-            return;
-        }
-    }
-    memcpy(iosock->writebuf.buffer + iosock->writebuf.bufpos, data, datalen);
-    iosock->writebuf.bufpos += datalen;
-       if((iosock->flags & IOSOCKETFLAG_ACTIVE))
-               engine->update(iosock);
-}
-
-void iosocket_write(struct IOSocket *iosocket, const char *line) {
-       size_t linelen = strlen(line);
-    iohandler_send(iosocket, line, linelen);
-}
-
-void iosocket_printf(struct IOSocket *iosocket, const char *text, ...) {
-       va_list arg_list;
-    char sendBuf[IOSOCKET_LINE_LEN];
-    int pos;
-    sendBuf[0] = '\0';
-    va_start(arg_list, text);
-    pos = vsnprintf(sendBuf, IOSOCKET_LINE_LEN - 2, text, arg_list);
-    va_end(arg_list);
-    if (pos < 0 || pos > (IOSOCKET_LINE_LEN - 2)) pos = IOSOCKET_LINE_LEN - 2;
-    sendBuf[pos] = '\n';
-    sendBuf[pos+1] = '\0';
-    iohandler_send(iosocket, sendBuf, pos+1);
-}
-
-
-
-
-
diff --git a/src/IOSockets.h b/src/IOSockets.h
deleted file mode 100644 (file)
index 79f945e..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-/* IOSockets.h - IOMultiplexer v2
- * Copyright (C) 2014  Philipp Kreil (pk910)
- * 
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License 
- * along with this program. If not, see <http://www.gnu.org/licenses/>. 
- */
-#ifndef _IOSockets_h
-#define _IOSockets_h
-#ifndef _IOHandler_internals
-#include "IOHandler.h"
-#else
-
-#define IOSOCKET_LINE_LEN 1024
-
-#define IOSOCKETFLAG_ACTIVE           0x0001
-#define IOSOCKETFLAG_LISTENING        0x0002
-#define IOSOCKETFLAG_PENDING_BINDDNS  0x0004
-#define IOSOCKETFLAG_PENDING_DESTDNS  0x0008
-#define IOSOCKETFLAG_DNSDONE_BINDDNS  0x0010
-#define IOSOCKETFLAG_DNSDONE_DESTDNS  0x0020
-#define IOSOCKETFLAG_DNSERROR         0x0040
-#define IOSOCKETFLAG_IPV6SOCKET       0x0080
-#define IOSOCKETFLAG_PARENT_PUBLIC    0x0100
-#define IOSOCKETFLAG_PARENT_DNSENGINE 0x0200
-#define IOSOCKETFLAG_SSLSOCKET        0x0400 /* use ssl after connecting */
-#define IOSOCKETFLAG_SHUTDOWN         0x0800 /* disconnect pending */
-
-struct IODNSAddress;
-struct IOSocketBuffer;
-struct IOSSLDescriptor;
-struct _IODNSQuery;
-
-struct IOSocketDNSLookup {
-       unsigned int bindlookup : 1;
-       char hostname[256];
-       struct _IOSocket *iosocket;
-       struct _IODNSQuery *query;
-       struct IODNSResult *result;
-};
-
-struct _IOSocket {
-    int fd;
-       
-       unsigned int socket_flags : 16;
-       
-       union {
-               struct IODNSAddress addr;
-               struct IOSocketDNSLookup *addrlookup;
-       } bind;
-       union {
-               struct IODNSAddress addr;
-               struct IOSocketDNSLookup *addrlookup;
-       } dest;
-       
-       unsigned int port : 16;
-       
-       struct IOSocketBuffer readbuf;
-    struct IOSocketBuffer writebuf;
-       
-       struct IOSSLDescriptor *sslnode;
-       
-       void *parent;
-       
-       struct _IOSocket *next, *prev;
-};
-
-void _init_sockets();
-void iosocket_lookup_callback(struct IOSocketDNSLookup *lookup, struct IODNSEvent *event);
-
-#endif
-
-struct IOSocketEvent;
-
-#define IOSOCKET_CALLBACK(NAME) void NAME(struct IOSocketEvent *event)
-typedef IOSOCKET_CALLBACK(iosocket_callback);
-
-enum IOSocketStatus { 
-    IOSOCKET_CLOSED, /* descriptor is dead (socket waiting for removal or timer) */
-    IOSOCKET_LISTENING, /* descriptor is waiting for connections (server socket) */
-    IOSOCKET_CONNECTING, /* descriptor is waiting for connection approval (connecting client socket) */
-    IOSOCKET_CONNECTED /* descriptor is connected (connected client socket) */
-};
-
-enum IOSocketEventType {
-    IOSOCKETEVENT_IGNORE,
-    IOSOCKETEVENT_RECV, /* client socket received something (read_lines == 1  =>  recv_str valid;  read_lines == 0  =>  recv_buf valid) */
-    IOSOCKETEVENT_CONNECTED, /* client socket connected successful */
-    IOSOCKETEVENT_NOTCONNECTED, /* client socket could not connect (errid valid) */
-    IOSOCKETEVENT_CLOSED, /* client socket lost connection (errid valid) */
-    IOSOCKETEVENT_ACCEPT, /* server socket accepted new connection (accept_socket valid) */
-    IOSOCKETEVENT_SSLFAILED, /* failed to initialize SSL session */
-       IOSOCKETEVENT_DNSFAILED /* failed to lookup DNS information */
-};
-
-struct IOSocket {
-       void *iosocket;
-       
-       enum IOSocketStatus status;
-       int listening : 1;
-       int ssl : 1;
-       int read_lines : 1;
-       
-       void *data;
-       iosocket_callback *callback;
-};
-
-struct IOSocketBuffer {
-    char *buffer;
-    size_t bufpos, buflen;
-};
-
-struct IOSocketEvent {
-    enum IOSocketEventType type;
-    struct IOSocket *socket;
-    union {
-        char *recv_str;
-               struct IOSocketBuffer *recv_buf;
-        int errid;
-        struct IOSocket *accept_socket;
-    } data;
-};
-
-
-#define IOSOCKET_ADDR_IPV4 0x01
-#define IOSOCKET_ADDR_IPV6 0x02 /* overrides IOSOCKET_ADDR_IPV4 */
-
-struct IOSocket *iosocket_connect(const char *hostname, unsigned int port, int ssl, const char *bindhost, iosocket_callback *callback);
-struct IOSocket *iosocket_connect_flags(const char *hostname, unsigned int port, int ssl, const char *bindhost, iosocket_callback *callback, int flags);
-struct IOSocket *iosocket_listen(const char *hostname, unsigned int port, iosocket_callback *callback);
-struct IOSocket *iosocket_listen_flags(const char *hostname, unsigned int port, iosocket_callback *callback, int flags);
-struct IOSocket *iosocket_listen_ssl(const char *hostname, unsigned int port, const char *certfile, const char *keyfile, iosocket_callback *callback);
-struct IOSocket *iosocket_listen_ssl_flags(const char *hostname, unsigned int port, const char *certfile, const char *keyfile, iosocket_callback *callback, int flags);
-void iosocket_write(struct IOSocket *iosocket, const char *line);
-void iosocket_send(struct IOSocket *iosocket, const char *data, size_t datalen);
-void iosocket_printf(struct IOSocket *iosocket, const char *text, ...);
-void iohandler_close(struct IOSocket *iosocket);
-
-#endif
diff --git a/src/IOTimer.c b/src/IOTimer.c
deleted file mode 100644 (file)
index 24545cd..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-/* IOTimer.c - IOMultiplexer v2
- * Copyright (C) 2014  Philipp Kreil (pk910)
- * 
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License 
- * along with this program. If not, see <http://www.gnu.org/licenses/>. 
- */
-#define _IOHandler_internals
-#include "IOInternal.h"
-#include "IOHandler.h"
-#include "IOTimer.h"
-#include "IOLog.h"
-
-#ifdef HAVE_PTHREAD_H
-static pthread_mutex_t iotimer_sync;
-#endif
-
-#define timeval_is_bigger(x,y) ((x->tv_sec > y->tv_sec) || (x->tv_sec == y->tv_sec && x->tv_usec > y->tv_usec))
-#define timeval_is_smaler(x,y) ((x->tv_sec < y->tv_sec) || (x->tv_sec == y->tv_sec && x->tv_usec < y->tv_usec))
-
-static void _rearrange_timer(struct IOTimerDescriptor *timer);
-static void _autoreload_timer(struct IOTimerDescriptor *timer);
-
-struct _IOTimerDescriptor *iotimer_sorted_descriptors;
-
-/* public functions */
-
-struct IOTimerDescriptor iotimer_create(struct timeval *timeout) {
-       struct IOTimerDescriptor *descriptor = calloc(1, sizeof(*descriptor));
-    if(!descriptor) {
-        iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
-        return NULL;
-    }
-       struct _IOTimerDescriptor *timer = _create_timer(timeout);
-       if(!timer) {
-               free(descriptor);
-               return NULL;
-       }
-       timer->parent = descriptor;
-       timer->flags |= IOTIMERFLAG_PARENT_PUBLIC;
-       descriptor->iotimer = timer;
-       
-       return descriptor;
-}
-
-void iotimer_start(struct IOTimerDescriptor *descriptor) {
-       struct _IOTimerDescriptor *timer = descriptor->iotimer;
-       if(timer == NULL) {
-               iolog_trigger(IOLOG_WARNING, "called iotimer_set_autoreload for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
-               return;
-       }
-       timer->flags |= IOTIMERFLAG_ACTIVE;
-       if(!(timer->flags & IOTIMERFLAG_IN_LIST))
-               _trigger_timer(timer);
-}
-
-void iotimer_set_autoreload(struct IOTimerDescriptor *descriptor, struct timeval *autoreload) {
-       struct _IOTimerDescriptor *timer = descriptor->iotimer;
-       if(timer == NULL) {
-               iolog_trigger(IOLOG_WARNING, "called iotimer_set_autoreload for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
-               return;
-       }
-       if(autoreload) {
-               timer->flags |= IOTIMERFLAG_PERIODIC;
-               timer->autoreload = *autoreload;
-               
-               if(!(timer->flags & IOTIMERFLAG_IN_LIST)) {
-                       struct timeval ctime;
-                       gettimeofday(&ctime, NULL);
-                       timer->timeout = ctime;
-                       _autoreload_timer(timer);
-               }
-       } else {
-               timer->flags &= ~IOTIMERFLAG_PERIODIC;
-       }
-}
-
-void iotimer_set_callback(struct IOTimerDescriptor *descriptor, iotimer_callback *callback) {
-       descriptor->callback = callback;
-}
-
-void iotimer_destroy(struct IOTimerDescriptor *descriptor) {
-       struct _IOTimerDescriptor *timer = descriptor->iotimer;
-       if(timer == NULL) {
-               iolog_trigger(IOLOG_WARNING, "called iotimer_destroy for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
-               return;
-       }
-       descriptor->iotimer = NULL;
-       _destroy_timer(timer);
-       
-       iogc_add(descriptor);
-}
-
-/* internal functions */
-void _init_timers() {
-       IOTHREAD_MUTEX_INIT(iotimer_sync);
-}
-
-struct _IOTimerDescriptor _create_timer(struct timeval *timeout) {
-       struct _IOTimerDescriptor *timer = calloc(1, sizeof(*timer));
-    if(!timer) {
-        iolog_trigger(IOLOG_ERROR, "could not allocate memory for _IOTimerDescriptor in %s:%d", __FILE__, __LINE__);
-        return NULL;
-    }
-       if(timeout) {
-               timer->timeout = *timeout;
-               _rearrange_timer(timer);
-       }
-       return timer;
-}
-
-static void _rearrange_timer(struct IOTimerDescriptor *timer) {
-       IOSYNCHRONIZE(iotimer_sync);
-       if((timer->flags & IOTIMERFLAG_IN_LIST)) {
-               if(timer->prev == NULL)
-                       iotimer_sorted_descriptors = timer->next;
-               else
-                       timer->prev->next = timer->next;
-               if(timer->next != NULL)
-                       timer->next->prev = timer->prev;
-       }
-       struct _IOTimerDescriptor *ctimer;
-       for(ctimer = iotimer_sorted_descriptors; ctimer;) {
-               if(timeval_is_bigger(&ctimer->timeout, &timer->timeout)) {
-                       timer->next = ctimer;
-                       timer->prev = ctimer->prev;
-                       if(ctimer->prev)
-                               ctimer->prev->next = timer;
-                       else
-                               iotimer_sorted_descriptors = timer;
-                       ctimer->prev = timer;
-                       break
-               }
-               else if(ctimer->next == NULL) {
-                       ctimer->next = timer;
-                       timer->prev = ctimer;
-                       break;
-               }
-       }
-       if(ctimer == NULL)
-               iotimer_sorted_descriptors = timer;
-       timer->flags |= IOTIMERFLAG_IN_LIST;
-       IODESYNCHRONIZE(iotimer_sync);
-}
-
-void _destroy_timer(struct _IOTimerDescriptor *timer) {
-       if((timer->flags & IOTIMERFLAG_IN_LIST)) {
-               IOSYNCHRONIZE(iotimer_sync);
-               if(timer->prev == NULL)
-                       iotimer_sorted_descriptors = timer->next;
-               else
-                       timer->prev->next = timer->next;
-               if(timer->next != NULL)
-                       timer->next->prev = timer->prev;
-               IODESYNCHRONIZE(iotimer_sync);
-       }
-       free(timer);
-}
-
-static void _autoreload_timer(struct IOTimerDescriptor *timer) {
-       timer->timeout.tv_usec += timer->autoreload.tv_usec;
-       timer->timeout.tv_sec += timer->autoreload.tv_sec;
-       if(timer->timeout.tv_usec > 1000000) {
-               timer->timeout.tv_sec += (timer->timeout.tv_usec / 1000000);
-               timer->timeout.tv_usec %= 1000000;
-       }
-       _rearrange_timer(timer);
-}
-
diff --git a/src/IOTimer.h b/src/IOTimer.h
deleted file mode 100644 (file)
index b7bd71a..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/* IOTimer.h - IOMultiplexer v2
- * Copyright (C) 2014  Philipp Kreil (pk910)
- * 
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License 
- * along with this program. If not, see <http://www.gnu.org/licenses/>. 
- */
-#ifndef _IOTimer_h
-#define _IOTimer_h
-#ifndef _IOHandler_internals
-#include "IOHandler.h"
-#else
-
-#define IOTIMERFLAG_PERIODIC       0x01
-#define IOTIMERFLAG_ACTIVE         0x02
-#define IOTIMERFLAG_IN_LIST        0x04
-#define IOTIMERFLAG_PARENT_PUBLIC  0x08
-#define IOTIMERFLAG_PARENT_SOCKET  0x10
-
-struct _IOTimerDescriptor;
-
-extern struct _IOTimerDescriptor *iotimer_sorted_descriptors;
-
-struct _IOTimerDescriptor {
-    unsigned int flags : 8;
-    void *parent; 
-    
-    struct timeval timeout;
-    struct timeval autoreload;
-    
-    struct _IOTimerDescriptor *prev, *next;
-};
-
-void _init_timers();
-struct _IOTimerDescriptor _create_timer(struct timeval timeout);
-void _destroy_timer(struct _IOTimerDescriptor *timer);
-
-#endif
-
-#define IOTIMER_CALLBACK(NAME) void NAME(struct IOTimerDescriptor *iotimer)
-typedef IOTIMER_CALLBACK(iotimer_callback);
-
-struct IOTimerDescriptor {
-    void *iotimer; /* struct _IOTimerDescriptor */
-    
-    iotimer_callback *callback;
-    void *data;
-};
-
-struct IOTimerDescriptor iotimer_create(struct timeval *timeout);
-void iotimer_start(struct IOTimerDescriptor *iotimer);
-void iotimer_set_autoreload(struct IOTimerDescriptor *iotimer, struct timeval *autoreload);
-void iotimer_set_callback(struct IOTimerDescriptor *iotimer, iotimer_callback *callback);
-void iotimer_destroy(struct IOTimerDescriptor *iotimer);
-
-#endif
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644 (file)
index 0000000..58909b1
--- /dev/null
@@ -0,0 +1,3 @@
+##Process this file with automake to create Makefile.in
+ACLOCAL_AMFLAGS = -I m4
+SUBDIRS = IOHandler IOHandler_test
diff --git a/src/compat/utime.c b/src/compat/utime.c
deleted file mode 100644 (file)
index 2f919fc..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef HAVE_USLEEP
-
-#ifdef HAVE_SELECT
-
-#ifdef HAVE_SYS_SELECT_H
-# include <sys/select.h>
-#else
-# include <sys/time.h>
-# include <sys/types.h>
-# include <unistd.h>
-#endif
-
-void usleep(long usec)
-{
-        struct timeval tv;
-
-        tv.tv_sec = usec / 1000000;
-        tv.tv_usec = usec % 1000000;
-        select(0, NULL, NULL, NULL, &tv);
-}
-
-#elif defined WIN32
-
-/* usleep implementation from FreeSCI */
-
-#include <windows.h>
-
-void usleep (long usec)
-{
-        LARGE_INTEGER lFrequency;
-        LARGE_INTEGER lEndTime;
-        LARGE_INTEGER lCurTime;
-
-        QueryPerformanceFrequency (&lFrequency);
-        if (lFrequency.QuadPart) {
-                QueryPerformanceCounter (&lEndTime);
-                lEndTime.QuadPart += (LONGLONG) usec *
-                                        lFrequency.QuadPart / 1000000;
-                do {
-                        QueryPerformanceCounter (&lCurTime);
-                        Sleep(0);
-                } while (lCurTime.QuadPart < lEndTime.QuadPart);
-        }
-}
-
-#endif
-
-#endif /* !HAVE_USLEEP */
\ No newline at end of file
diff --git a/src/test/socket/Makefile b/src/test/socket/Makefile
deleted file mode 100644 (file)
index 724e34b..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-
-CC      = gcc
-CFLAGS  = -g -O0 -Wall -Wshadow -Werror -DHAVE_PTHREAD_H
-LDFLAGS = -lws2_32 -lpthread
-
-OBJ     = ../../IOEngine_epoll.o ../../IOEngine_kevent.o ../../IOEngine_select.o ../../IOEngine_win32.o ../../IOHandler.o ../../IOHandler_SSL.o iotest.o
-
-all: $(OBJ)
-       $(CC) $(CFLAGS) -oiotest $(OBJ) $(LDFLAGS)
-
-%.o: %.c
-       $(CC) $(CFLAGS) -o$@ -c $<
diff --git a/src/test/socket/iotest.c b/src/test/socket/iotest.c
deleted file mode 100644 (file)
index 15f32f4..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/* main.c - IOMultiplexer
- * Copyright (C) 2012  Philipp Kreil (pk910)
- * 
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License 
- * along with this program. If not, see <http://www.gnu.org/licenses/>. 
- */
-
-#include <stdio.h>
-#include "../IOHandler.h"
-
-static IOHANDLER_CALLBACK(io_callback);
-static IOHANDLER_LOG_BACKEND(io_log);
-
-static struct IODescriptor *irc_iofd = NULL;
-
-int main(int argc, char *argv[]) {
-    iolog_backend = io_log;
-    
-    irc_iofd = iohandler_connect("pk910.de", 6667, 0, NULL, io_callback);
-    
-    struct IODescriptor *iofd;
-    iofd = iohandler_add(0, IOTYPE_STDIN, NULL, io_callback);
-    iofd->read_lines = 1;
-    
-    while(1) {
-        iohandler_poll();
-    }
-}
-
-static IOHANDLER_CALLBACK(io_callback) {
-    switch(event->type) {
-        case IOEVENT_CONNECTED:
-            printf("[connect]\n");
-            break;
-        case IOEVENT_CLOSED:
-            printf("[disconnect]\n");
-            break;
-        case IOEVENT_RECV:
-            if(event->iofd->type == IOTYPE_STDIN) {
-                iohandler_printf(irc_iofd, "%s\n", event->data.recv_str);
-                printf("[out] %s\n", event->data.recv_str);
-            } else
-                printf("[in] %s\n", event->data.recv_str);
-            break;
-        
-        default:
-            break;
-    }
-}
-
-static IOHANDLER_LOG_BACKEND(io_log) {
-    //printf("%s", line);
-}
diff --git a/src/test/timer/Makefile b/src/test/timer/Makefile
deleted file mode 100644 (file)
index 724e34b..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-
-CC      = gcc
-CFLAGS  = -g -O0 -Wall -Wshadow -Werror -DHAVE_PTHREAD_H
-LDFLAGS = -lws2_32 -lpthread
-
-OBJ     = ../../IOEngine_epoll.o ../../IOEngine_kevent.o ../../IOEngine_select.o ../../IOEngine_win32.o ../../IOHandler.o ../../IOHandler_SSL.o iotest.o
-
-all: $(OBJ)
-       $(CC) $(CFLAGS) -oiotest $(OBJ) $(LDFLAGS)
-
-%.o: %.c
-       $(CC) $(CFLAGS) -o$@ -c $<
diff --git a/src/test/timer/iotest.c b/src/test/timer/iotest.c
deleted file mode 100644 (file)
index 17a91ec..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/* main.c - IOMultiplexer
- * Copyright (C) 2012  Philipp Kreil (pk910)
- * 
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License 
- * along with this program. If not, see <http://www.gnu.org/licenses/>. 
- */
-
-#include <stdio.h>
-#include "../../IOHandler.h"
-
-#define TEST_DURATION 100
-
-static IOHANDLER_CALLBACK(io_callback);
-static IOHANDLER_LOG_BACKEND(io_log);
-
-static struct timeval test_clock1, test_clock2;
-static int timercount;
-
-void add_timer(int ms) {
-    struct timeval timeout;
-    gettimeofday(&timeout, NULL);
-    timeout.tv_usec += (ms % 1000) * 1000;
-    timeout.tv_sec += (ms / 1000);
-    if(timeout.tv_usec > 1000000) {
-        timeout.tv_usec -= 1000000;
-        timeout.tv_sec++;
-    }
-    iohandler_timer(timeout, io_callback);
-}
-
-int main(int argc, char *argv[]) {
-    iolog_backend = io_log;
-    
-    iohandler_set(IOHANDLER_SETTING_HIGH_PRECISION_TIMER, 1);
-    
-    gettimeofday(&test_clock1, NULL);
-    gettimeofday(&test_clock2, NULL);
-    //add_timer(TEST_DURATION);
-    iohandler_constant_timer(TEST_DURATION, io_callback);
-    timercount = 0;
-    
-    printf("[timer 0] %ld.%ld\n", test_clock1.tv_sec, test_clock1.tv_usec);
-    
-    while(1) {
-        iohandler_poll();
-    }
-}
-
-static IOHANDLER_CALLBACK(io_callback) {
-    struct timeval curr_time;
-    int diff1;
-    double diff2;
-    switch(event->type) {
-        case IOEVENT_TIMEOUT:
-            //add_timer(TEST_DURATION);
-            timercount++;
-            gettimeofday(&curr_time, NULL);
-            diff1 = (curr_time.tv_sec - test_clock1.tv_sec) * 1000 + ((curr_time.tv_usec - test_clock1.tv_usec) / 1000);
-            diff2 = (curr_time.tv_sec - test_clock2.tv_sec) * 1000 + ((curr_time.tv_usec - test_clock2.tv_usec) / 1000.0);
-            diff2 -= (timercount * TEST_DURATION);
-            gettimeofday(&test_clock1, NULL);
-            printf("[timer %03d] %ld.%06ld [%d ms]  accuracy: %f ms\n", timercount, curr_time.tv_sec, curr_time.tv_usec, diff1, diff2);
-            break;
-        default:
-            break;
-    }
-}
-
-static IOHANDLER_LOG_BACKEND(io_log) {
-    //printf("%s", line);
-}