From 78c9b3cbb2ecafa3b275c3eeafcf80796b7b3138 Mon Sep 17 00:00:00 2001 From: pk910 Date: Sat, 8 Mar 2014 01:03:37 +0100 Subject: [PATCH] [IOMultiplexerV2] started to implement c-ares backend --- src/IOHandler/IODNSEngine_cares.c | 196 +++++++++++++++++++++++++++- src/IOHandler/IODNSEngine_default.c | 1 + src/IOHandler/IODNSLookup.c | 5 + src/IOHandler/IODNSLookup.h | 4 +- src/IOHandler/IOEngine_select.c | 7 +- src/IOHandler/IOSSLBackend.c | 2 +- src/IOHandler/IOSockets.c | 15 ++- src/IOHandler/IOSockets.h | 14 +- src/IOHandler/IOTimer.c | 14 ++ src/IOHandler/IOTimer.h | 1 + src/IOHandler_test/socket/iotest.c | 4 +- 11 files changed, 244 insertions(+), 19 deletions(-) diff --git a/src/IOHandler/IODNSEngine_cares.c b/src/IOHandler/IODNSEngine_cares.c index 2bbce18..447d8c1 100644 --- a/src/IOHandler/IODNSEngine_cares.c +++ b/src/IOHandler/IODNSEngine_cares.c @@ -18,16 +18,189 @@ #include "IOInternal.h" #include "IOHandler.h" #include "IODNSLookup.h" +#include "IOLog.h" +#include "IOSockets.h" +#include "IOTimer.h" + +#ifdef HAVE_ARES_H +#include +#include +#include +#ifdef WIN32 +#define _WIN32_WINNT 0x501 +#include +#include +#elif defined HAVE_SYS_SELECT_H +#include +#endif + +struct dnsengine_cares_socket { + struct _IOSocket *iosock; + int want_read : 1; + int want_write : 1; +}; + +static IOTIMER_CALLBACK(dnsengine_cares_timer_callback); + +static ares_channel dnsengine_cares_channel; +static struct dnsengine_cares_socket dnsengine_cares_sockets[ARES_GETSOCK_MAXNUM]; +static struct IOTimerDescriptor *dnsengine_cares_timer = NULL; static int dnsengine_cares_init() { - /* TODO */ - return 0; + int res; + + // zero dnsengine_cares_sockets array + memset(dnsengine_cares_sockets, 0, sizeof(*dnsengine_cares_sockets) * ARES_GETSOCK_MAXNUM); + + // initialize cares + if((res = ares_init(&dnsengine_cares_channel)) != ARES_SUCCESS) { + iolog_trigger(IOLOG_ERROR, "Failed to initialize c-ares in %s:%d", __FILE__, __LINE__); + return 0; + } + return 0; /* backend not completed */ +} + +static void dnsengine_cares_update_sockets() { + int ares_socks[ARES_GETSOCK_MAXNUM]; + memset(ares_socks, 0, sizeof(*ares_socks) * ARES_GETSOCK_MAXNUM); + int sockreqs = ares_getsock(dnsengine_cares_channel, ares_socks, ARES_GETSOCK_MAXNUM); + int i, j, sockid, newsock, updatesock; + struct _IOSocket *iosock; + + //unregister "old" sockets + for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) { + if(!dnsengine_cares_sockets[i].iosock) + continue; + + //search matching ares_socks + sockid = -1; + for(j = 0; j < ARES_GETSOCK_MAXNUM; j++) { + if(dnsengine_cares_sockets[i].iosock->fd == ares_socks[j]) { + sockid = j; + break; + } + } + if(sockid == -1) { + //unregister socket + _free_socket(dnsengine_cares_sockets[i].iosock); + dnsengine_cares_sockets[i].iosock = NULL; + } + } + + //register new / update existing sockets + for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) { + if(!ares_socks[i]) + break; + + //search matching dnsengine_cares_socket + sockid = -1; + for(j = 0; j < ARES_GETSOCK_MAXNUM; j++) { + if(dnsengine_cares_sockets[j].iosock && dnsengine_cares_sockets[j].iosock->fd == ares_socks[i]) { + sockid = j; + break; + } + } + + if(sockid == -1) { + //append new socket + for(j = 0; j < ARES_GETSOCK_MAXNUM; j++) { + if(!dnsengine_cares_sockets[j].iosock) { + sockid = j; + break; + } + } + if(sockid == -1) { + iolog_trigger(IOLOG_ERROR, "Error in dnsengine_cares_update_sockets: could not find free dnsengine_cares_socket in %s:%d", __FILE__, __LINE__); + continue; + } + iosock = _create_socket(); + if(!iosock) + continue; + + //set up iosock + iosock->socket_flags |= IOSOCKETFLAG_PARENT_DNSENGINE | IOSOCKETFLAG_OVERRIDE_WANT_RW; + iosock->fd = ares_socks[i]; + dnsengine_cares_sockets[sockid].want_read = 0; + dnsengine_cares_sockets[sockid].want_write = 0; + + newsock = 1; + } else + newsock = 0; + + updatesock = 0; + if(dnsengine_cares_sockets[sockid].want_read ^ ARES_GETSOCK_READABLE(sockreqs, i)) { + if(ARES_GETSOCK_READABLE(sockreqs, i)) { + dnsengine_cares_sockets[sockid].iosock->socket_flags |= IOSOCKETFLAG_OVERRIDE_WANT_R; + dnsengine_cares_sockets[sockid].want_read = 1; + } else { + dnsengine_cares_sockets[sockid].iosock->socket_flags &= ~IOSOCKETFLAG_OVERRIDE_WANT_R; + dnsengine_cares_sockets[sockid].want_read = 0; + } + updatesock = 1; + } + if(dnsengine_cares_sockets[sockid].want_write ^ ARES_GETSOCK_WRITABLE(sockreqs, i)) { + if(ARES_GETSOCK_WRITABLE(sockreqs, i)) { + dnsengine_cares_sockets[sockid].iosock->socket_flags |= IOSOCKETFLAG_OVERRIDE_WANT_W; + dnsengine_cares_sockets[sockid].want_write = 1; + } else { + dnsengine_cares_sockets[sockid].iosock->socket_flags &= ~IOSOCKETFLAG_OVERRIDE_WANT_W; + dnsengine_cares_sockets[sockid].want_write = 0; + } + updatesock = 1; + } + if(updatesock || newsock) { + if(newsock) + iosocket_activate(dnsengine_cares_sockets[sockid].iosock); + else + iosocket_update(dnsengine_cares_sockets[sockid].iosock); + } + } +} + +static void dnsengine_cares_update_timeout() { + struct timeval timeout, now; + timeout.tv_sec = 60; + timeout.tv_usec = 0; + ares_timeout(dnsengine_cares_channel, &timeout, &timeout); + + gettimeofday(&now, NULL); + timeout.tv_sec += now.tv_sec; + timeout.tv_usec += now.tv_usec; + if(timeout.tv_usec > 1000000) { + timeout.tv_sec += 1; + timeout.tv_usec -= 1000000; + } + + if(dnsengine_cares_timer) + iotimer_set_timeout(dnsengine_cares_timer, &timeout); + else { + dnsengine_cares_timer = iotimer_create(&timeout); + iotimer_set_callback(dnsengine_cares_timer, dnsengine_cares_timer_callback); + iotimer_start(dnsengine_cares_timer); + } +} + +static IOTIMER_CALLBACK(dnsengine_cares_timer_callback) { + dnsengine_cares_timer = NULL; + ares_process_fd(dnsengine_cares_channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD); + dnsengine_cares_update_timeout(); + dnsengine_cares_update_sockets(); +} + +static void dnsengine_cares_socket_callback(struct _IOSocket *iosock, int wantread, int wantwrite) { + int socketfd = iosock->fd; + ares_process_fd(dnsengine_cares_channel, (wantread ? socketfd : ARES_SOCKET_BAD), (wantread ? socketfd : ARES_SOCKET_BAD)); + dnsengine_cares_update_timeout(); + dnsengine_cares_update_sockets(); } static void dnsengine_cares_stop() { - /* TODO */ + if(dnsengine_cares_timer) + iotimer_destroy(dnsengine_cares_timer); } + + static void dnsengine_cares_add(struct _IODNSQuery *iodns) { /* TODO */ } @@ -37,7 +210,7 @@ static void dnsengine_cares_remove(struct _IODNSQuery *iodns) { } static void dnsengine_cares_loop() { - /* TODO */ + /* empty */ } struct IODNSEngine dnsengine_cares = { @@ -47,4 +220,19 @@ struct IODNSEngine dnsengine_cares = { .add = dnsengine_cares_add, .remove = dnsengine_cares_remove, .loop = dnsengine_cares_loop, + .socket_callback = dnsengine_cares_socket_callback, }; + +#else + +struct IODNSEngine dnsengine_cares = { + .name = "c-ares", + .init = NULL, + .stop = NULL, + .add = NULL, + .remove = NULL, + .loop = NULL, + .socket_callback = NULL, +}; + +#endif diff --git a/src/IOHandler/IODNSEngine_default.c b/src/IOHandler/IODNSEngine_default.c index b9f3764..926a7d8 100644 --- a/src/IOHandler/IODNSEngine_default.c +++ b/src/IOHandler/IODNSEngine_default.c @@ -212,4 +212,5 @@ struct IODNSEngine dnsengine_default = { .add = dnsengine_default_add, .remove = dnsengine_default_remove, .loop = dnsengine_default_loop, + .socket_callback = NULL, }; diff --git a/src/IOHandler/IODNSLookup.c b/src/IOHandler/IODNSLookup.c index e39a9cf..71d014d 100644 --- a/src/IOHandler/IODNSLookup.c +++ b/src/IOHandler/IODNSLookup.c @@ -90,6 +90,11 @@ void _stop_dnsquery(struct _IODNSQuery *query) { _free_dnsquery(query); } +void iodns_socket_callback(struct _IOSocket *iosock, int wantread, int wantwrite) { + if(dnsengine && dnsengine->socket_callback) + dnsengine->socket_callback(iosock, wantread, wantwrite); +} + void iodns_event_callback(struct _IODNSQuery *query, enum IODNSEventType state) { if((query->flags & IODNSFLAG_PARENT_PUBLIC)) { struct IODNSQuery *descriptor = query->parent; diff --git a/src/IOHandler/IODNSLookup.h b/src/IOHandler/IODNSLookup.h index 29574cb..72ac5dc 100644 --- a/src/IOHandler/IODNSLookup.h +++ b/src/IOHandler/IODNSLookup.h @@ -64,6 +64,7 @@ extern struct _IODNSQuery *iodnsquery_last; #define IODNSFLAG_PARENT_SOCKET 0x08 struct IODNSResult; +struct _IOSocket; struct _IODNSQuery { void *query; @@ -89,6 +90,7 @@ struct IODNSEngine { void (*add)(struct _IODNSQuery *query); void (*remove)(struct _IODNSQuery *query); void (*loop)(); + void (*socket_callback)(struct _IOSocket *iosock, int readable, int writeable); }; void _init_iodns(); @@ -100,8 +102,8 @@ void _stop_dnsquery(struct _IODNSQuery *query); /* call only from engines! */ enum IODNSEventType; void _free_dnsquery(struct _IODNSQuery *query); +void iodns_socket_callback(struct _IOSocket *iosock, int wantread, int wantwrite); void iodns_event_callback(struct _IODNSQuery *query, enum IODNSEventType state); - void iodns_poll(); #endif diff --git a/src/IOHandler/IOEngine_select.c b/src/IOHandler/IOEngine_select.c index 0d95116..b725572 100644 --- a/src/IOHandler/IOEngine_select.c +++ b/src/IOHandler/IOEngine_select.c @@ -23,13 +23,14 @@ #include #include +#include +#include #ifdef WIN32 #define _WIN32_WINNT 0x501 #include #include -#else -#include -#include +#elif defined HAVE_SYS_SELECT_H +#include #endif /* compat */ diff --git a/src/IOHandler/IOSSLBackend.c b/src/IOHandler/IOSSLBackend.c index 5fe568e..6e59545 100644 --- a/src/IOHandler/IOSSLBackend.c +++ b/src/IOHandler/IOSSLBackend.c @@ -250,7 +250,7 @@ void iossl_init() {}; void iossl_connect(struct _IOSocket *iosock) {}; void iossl_listen(struct _IOSocket *iosock, const char *certfile, const char *keyfile) {}; void iossl_client_handshake(struct _IOSocket *iosock) {}; -void iossl_client_accepted(struct _IOSocket *iosock, struct IODescriptor *client_iofd) {}; +void iossl_client_accepted(struct _IOSocket *iosock, struct _IOSocket *client_iofd) {}; void iossl_server_handshake(struct _IOSocket *iosock) {}; void iossl_disconnect(struct _IOSocket *iosock) {}; int iossl_read(struct _IOSocket *iosock, char *buffer, int len) { return 0; }; diff --git a/src/IOHandler/IOSockets.c b/src/IOHandler/IOSockets.c index 4a7da99..b844d64 100644 --- a/src/IOHandler/IOSockets.c +++ b/src/IOHandler/IOSockets.c @@ -20,6 +20,7 @@ #include "IOSockets.h" #include "IOLog.h" #include "IODNSLookup.h" +#include "IOSSLBackend.h" #ifdef WIN32 #define _WIN32_WINNT 0x501 @@ -51,8 +52,6 @@ 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); @@ -147,20 +146,26 @@ void _free_socket(struct _IOSocket *iosock) { free(iosock); } -static void iosocket_activate(struct _IOSocket *iosock) { +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) { +void iosocket_deactivate(struct _IOSocket *iosock) { if(!(iosock->socket_flags & IOSOCKETFLAG_ACTIVE)) return; iosock->socket_flags &= ~IOSOCKETFLAG_ACTIVE; engine->remove(iosock); } +void iosocket_update(struct _IOSocket *iosock) { + if(!(iosock->socket_flags & IOSOCKETFLAG_ACTIVE)) + return; + engine->update(iosock); +} + static void iosocket_increase_buffer(struct IOSocketBuffer *iobuf, size_t required) { if(iobuf->buflen >= required) return; char *new_buf; @@ -1056,7 +1061,7 @@ void iosocket_events_callback(struct _IOSocket *iosock, int readable, int writea iosocket_close(iosocket); } else if((iosock->socket_flags & IOSOCKETFLAG_PARENT_DNSENGINE)) { - //TODO: IODNS callback + iodns_socket_callback(iosock, readable, writeable); } } diff --git a/src/IOHandler/IOSockets.h b/src/IOHandler/IOSockets.h index f2d01e2..d38bcd7 100644 --- a/src/IOHandler/IOSockets.h +++ b/src/IOHandler/IOSockets.h @@ -127,6 +127,12 @@ struct _IOSocket { }; void _init_sockets(); +struct _IOSocket *_create_socket(); +void _free_socket(struct _IOSocket *iosock); +void iosocket_activate(struct _IOSocket *iosock); +void iosocket_deactivate(struct _IOSocket *iosock); +void iosocket_update(struct _IOSocket *iosock); + 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); @@ -134,14 +140,14 @@ void iosocket_events_callback(struct _IOSocket *iosock, int readable, int writea #define iosocket_wants_reads(IOSOCK) \ (\ ((IOSOCK->socket_flags & (IOSOCKETFLAG_SSL_READHS | IOSOCKETFLAG_SSL_WRITEHS)) && !(IOSOCK->socket_flags & IOSOCKETFLAG_SSL_WANTWRITE)) || \ - (!(IOSOCK->socket_flags & IOSOCKETFLAG_OVERRIDE_WANT_RW) || \ - (IOSOCK->socket_flags & (IOSOCKETFLAG_OVERRIDE_WANT_RW | IOSOCKETFLAG_OVERRIDE_WANT_R) == (IOSOCKETFLAG_OVERRIDE_WANT_RW | IOSOCKETFLAG_OVERRIDE_WANT_R)) \ + (!(IOSOCK->socket_flags & IOSOCKETFLAG_OVERRIDE_WANT_RW)) || \ + ((IOSOCK->socket_flags & (IOSOCKETFLAG_OVERRIDE_WANT_RW | IOSOCKETFLAG_OVERRIDE_WANT_R)) == (IOSOCKETFLAG_OVERRIDE_WANT_RW | IOSOCKETFLAG_OVERRIDE_WANT_R)) \ ) #define iosocket_wants_writes(IOSOCK) \ (\ - (IOSOCK->socket_flags & (IOSOCKETFLAG_SSL_READHS | IOSOCKETFLAG_SSL_WRITEHS | IOSOCKETFLAG_SSL_WANTWRITE) > IOSOCKETFLAG_SSL_WANTWRITE) || \ + ((IOSOCK->socket_flags & (IOSOCKETFLAG_SSL_READHS | IOSOCKETFLAG_SSL_WRITEHS | IOSOCKETFLAG_SSL_WANTWRITE)) > IOSOCKETFLAG_SSL_WANTWRITE) || \ (!(IOSOCK->socket_flags & IOSOCKETFLAG_OVERRIDE_WANT_RW) && (IOSOCK->writebuf.bufpos || (IOSOCK->socket_flags & IOSOCKETFLAG_CONNECTING))) || \ - (IOSOCK->socket_flags & (IOSOCKETFLAG_OVERRIDE_WANT_RW | IOSOCKETFLAG_OVERRIDE_WANT_W) == (IOSOCKETFLAG_OVERRIDE_WANT_RW | IOSOCKETFLAG_OVERRIDE_WANT_W)) \ + ((IOSOCK->socket_flags & (IOSOCKETFLAG_OVERRIDE_WANT_RW | IOSOCKETFLAG_OVERRIDE_WANT_W)) == (IOSOCKETFLAG_OVERRIDE_WANT_RW | IOSOCKETFLAG_OVERRIDE_WANT_W)) \ ) #endif diff --git a/src/IOHandler/IOTimer.c b/src/IOHandler/IOTimer.c index ec90d39..8c4adc7 100644 --- a/src/IOHandler/IOTimer.c +++ b/src/IOHandler/IOTimer.c @@ -80,6 +80,20 @@ void iotimer_set_autoreload(struct IOTimerDescriptor *descriptor, struct timeval } } +void iotimer_set_timeout(struct IOTimerDescriptor *descriptor, struct timeval *timeout) { + struct _IOTimerDescriptor *timer = descriptor->iotimer; + if(timer == NULL) { + iolog_trigger(IOLOG_WARNING, "called iotimer_set_timeout for destroyed IOTimerDescriptor in %s:%d", __FILE__, __LINE__); + return; + } + if(!timeout) { + iolog_trigger(IOLOG_WARNING, "called iotimer_set_timeout without timeout given in %s:%d", __FILE__, __LINE__); + return; + } + timer->timeout = *timeout; + _rearrange_timer(timer); +} + void iotimer_set_callback(struct IOTimerDescriptor *descriptor, iotimer_callback *callback) { descriptor->callback = callback; } diff --git a/src/IOHandler/IOTimer.h b/src/IOHandler/IOTimer.h index c173282..31576cc 100644 --- a/src/IOHandler/IOTimer.h +++ b/src/IOHandler/IOTimer.h @@ -64,6 +64,7 @@ struct IOTimerDescriptor { 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_timeout(struct IOTimerDescriptor *iotimer, struct timeval *timeout); void iotimer_set_callback(struct IOTimerDescriptor *iotimer, iotimer_callback *callback); void iotimer_destroy(struct IOTimerDescriptor *iotimer); diff --git a/src/IOHandler_test/socket/iotest.c b/src/IOHandler_test/socket/iotest.c index 9da8b2b..0069b02 100644 --- a/src/IOHandler_test/socket/iotest.c +++ b/src/IOHandler_test/socket/iotest.c @@ -51,7 +51,9 @@ static IOSOCKET_CALLBACK(io_callback) { case IOSOCKETEVENT_RECV: { struct IOSocketBuffer *recv_buf = event->data.recv_buf; - write(1, recv_buf->buffer, recv_buf->bufpos); + int i; + for(i = 0; i < recv_buf->bufpos; i++) + putchar(recv_buf->buffer[i]); recv_buf->bufpos = 0; printf("\n"); } -- 2.20.1