--- /dev/null
+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
--- /dev/null
+##Process this file with automake to create Makefile.in
+ACLOCAL_AMFLAGS = -I m4
+SUBDIRS = src
--- /dev/null
+#!/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"
--- /dev/null
+# 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
--- /dev/null
+Makefile.in
+Makefile
+++ /dev/null
-/* 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,
-};
+++ /dev/null
-/* 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,
-};
+++ /dev/null
-/* 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);
- }
-}
-
+++ /dev/null
-/* 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
+++ /dev/null
-/* 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;
- }
- }
-}
+++ /dev/null
-/* 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
+++ /dev/null
-/* 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 */
-}
-
+++ /dev/null
-/* 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
--- /dev/null
+.deps
+Makefile.in
+Makefile
+*.o
+*.a
--- /dev/null
+/* 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
--- /dev/null
+/* 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,
+};
--- /dev/null
+/* 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,
+};
--- /dev/null
+/* 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);
+ }
+}
+
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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,
+};
--- /dev/null
+/* 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
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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
--- /dev/null
+/* 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();
+}
+
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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) {
+
+}
--- /dev/null
+/* 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
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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
--- /dev/null
+/* 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;
+}
+
--- /dev/null
+/* 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
--- /dev/null
+##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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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
--- /dev/null
+##Process this file with automake to create Makefile.in
+ACLOCAL_AMFLAGS = -I m4
+SUBDIRS = socket timer
--- /dev/null
+.deps
+*.o
+iotest
--- /dev/null
+##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
+
--- /dev/null
+/* 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);
+}
--- /dev/null
+##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
+
--- /dev/null
+/* 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);
+}
+++ /dev/null
-/* 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
+++ /dev/null
-/* 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';
-
-
-}
+++ /dev/null
-/* 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
+++ /dev/null
-/* 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);
-}
-
-
-
-
-
+++ /dev/null
-/* 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
+++ /dev/null
-/* 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);
-}
-
+++ /dev/null
-/* 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
--- /dev/null
+##Process this file with automake to create Makefile.in
+ACLOCAL_AMFLAGS = -I m4
+SUBDIRS = IOHandler IOHandler_test
+++ /dev/null
-#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
+++ /dev/null
-
-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 $<
+++ /dev/null
-/* 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);
-}
+++ /dev/null
-
-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 $<
+++ /dev/null
-/* 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);
-}