From 2f09fcea846a47f2725afd5deb01db30da088190 Mon Sep 17 00:00:00 2001 From: Jan Vidar Krey Date: Wed, 20 Jan 2010 17:26:23 +0100 Subject: [PATCH] Added select() backend which can be used as a fallback if epoll is not available. --- GNUmakefile | 16 +- src/core/hub.c | 3 - src/core/hub.h | 4 - src/core/usermanager.c | 37 ---- src/network/backend.h | 2 + src/network/common.h | 6 +- src/network/connection.c | 51 ++++- src/network/connection.h | 8 + src/network/epoll.c | 105 ++--------- src/network/libevent.c | 399 --------------------------------------- src/network/select.c | 208 ++++++++++++++++++++ src/network/timer.c | 50 +++++ src/system.h | 7 +- src/tools/adcrush.c | 48 +---- src/tools/admin.c | 6 +- src/util/timeout.c | 2 +- 16 files changed, 344 insertions(+), 608 deletions(-) delete mode 100644 src/network/libevent.c create mode 100644 src/network/select.c create mode 100644 src/network/timer.c diff --git a/GNUmakefile b/GNUmakefile index eacb1c1..1f21a37 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -9,7 +9,6 @@ MV := mv RANLIB := ranlib CFLAGS += -pipe -Wall USE_SSL ?= NO -USE_LIBEVENT ?= NO USE_BIGENDIAN ?= AUTO BITS ?= AUTO SILENT ?= YES @@ -63,9 +62,6 @@ else MSG_CLEAN="Clean as a whistle" endif -# CFLAGS += -I/source/libevent -# LDFLAGS += -L/source/libevent - ifeq ($(RELEASE),YES) CFLAGS += -O3 -DNDEBUG GIT_REVISION ?= NO @@ -116,15 +112,6 @@ CFLAGS += -DSSL_SUPPORT LDLIBS += -lssl endif -ifeq ($(USE_LIBEVENT),YES) -CFLAGS += -DUSE_LIBEVENT -LDLIBS += -levent -ifneq ($(LIBEVENT_PATH),) -CFLAGS += -I$(LIBEVENT_PATH) -LDFLAGS += -L$(LIBEVENT_PATH) -endif -endif - ifeq ($(GIT_REVISION),YES) CFLAGS += -DGIT_REVISION=\"$(shell git show --abbrev-commit | head -n 1 | cut -f 2 -d " ")\" endif @@ -146,8 +133,9 @@ libuhub_SOURCES := \ src/core/usermanager.c \ src/network/connection.c \ src/network/epoll.c \ - src/network/libevent.c \ src/network/network.c \ + src/network/select.c \ + src/network/timer.c \ src/util/ipcalc.c \ src/util/list.c \ src/util/log.c \ diff --git a/src/core/hub.c b/src/core/hub.c index 171f40a..8b7ee15 100644 --- a/src/core/hub.c +++ b/src/core/hub.c @@ -622,9 +622,6 @@ void hub_shutdown_service(struct hub_info* hub) LOG_DEBUG("hub_shutdown_service()"); event_queue_shutdown(hub->queue); -#ifdef USE_LIBEVENT - event_del(&hub->ev_accept); -#endif net_con_close(hub->server); hub_free(hub->server); uman_shutdown(hub); diff --git a/src/core/hub.h b/src/core/hub.h index c66e27f..8eab77b 100644 --- a/src/core/hub.h +++ b/src/core/hub.h @@ -91,10 +91,6 @@ struct hub_logout_info struct hub_info { struct net_connection* server; -#ifdef USE_LIBEVENT - struct event ev_accept; - struct event ev_timer; -#endif struct hub_stats stats; struct event_queue* queue; struct hub_config* config; diff --git a/src/core/usermanager.c b/src/core/usermanager.c index 1db3b78..3c0eb36 100644 --- a/src/core/usermanager.c +++ b/src/core/usermanager.c @@ -70,28 +70,9 @@ void uman_print_stats(struct hub_info* hub) (int) hub->stats.net_rx_peak / 1024); } -#ifdef USERMANAGER_TIMER -#ifdef USE_LIBEVENT -static void timer_statistics(int fd, short ev, void *arg) -{ - struct hub_info* hub = (struct hub_info*) arg; - struct timeval timeout = { TIMEOUT_STATS, 0 }; - uman_update_stats(hub); - evtimer_set(&hub->ev_timer, timer_statistics, hub); - evtimer_add(&hub->ev_timer, &timeout); -} -#endif -#endif - - int uman_init(struct hub_info* hub) { struct hub_user_manager* users = NULL; -#ifdef USERMANAGER_TIMER -#ifdef USE_LIBEVENT - struct timeval timeout = { TIMEOUT_STATS, 0 }; -#endif -#endif if (!hub) return -1; @@ -110,16 +91,6 @@ int uman_init(struct hub_info* hub) } hub->users = users; - -#ifdef USERMANAGER_TIMER -#ifdef USE_LIBEVENT - if (net_get_evbase()) - { - evtimer_set(&hub->ev_timer, timer_statistics, hub); - evtimer_add(&hub->ev_timer, &timeout); - } -#endif -#endif // 0 return 0; } @@ -129,13 +100,6 @@ int uman_shutdown(struct hub_info* hub) if (!hub || !hub->users) return -1; -#ifdef USERMANAGER_TIMER -#ifdef USE_LIBEVENT - if (evtimer_pending(&hub->ev_timer, 0)) - evtimer_del(&hub->ev_timer); -#endif -#endif - if (hub->users->list) { list_clear(hub->users->list, &clear_user_list_callback); @@ -144,7 +108,6 @@ int uman_shutdown(struct hub_info* hub) sid_pool_destroy(hub->users->sids); hub_free(hub->users); hub->users = 0; - return 0; } diff --git a/src/network/backend.h b/src/network/backend.h index 550ef37..d3bf105 100644 --- a/src/network/backend.h +++ b/src/network/backend.h @@ -36,4 +36,6 @@ extern void net_backend_shutdown(); */ extern int net_backend_process(); +extern struct timeout_queue* net_backend_get_timeout_queue(); + #endif /* HAVE_UHUB_NETWORK_BACKEND_H */ diff --git a/src/network/common.h b/src/network/common.h index c60a46f..33fa2a9 100644 --- a/src/network/common.h +++ b/src/network/common.h @@ -1,7 +1,7 @@ #define NET_WANT_READ NET_EVENT_READ #define NET_WANT_WRITE NET_EVENT_WRITE -#define NET_WANT_ACCEPT 0x0008 +#define NET_WANT_ACCEPT NET_EVENT_READ #define NET_WANT_SSL_READ 0x0010 #define NET_WANT_SSL_WRITE 0x0020 #define NET_WANT_SSL_ACCEPT 0x0040 @@ -13,14 +13,12 @@ #define NET_INITIALIZED 0x2000 #define NET_TIMER_ENABLED 0x1000 -/* FIXME: Meant for debugging */ -#define NET_EVENT_SET 0x0800 - #define NET_CON_STRUCT_BASIC \ int sd; /** socket descriptor */ \ uint32_t flags; /** Connection flags */ \ void* ptr; /** data pointer */ \ net_connection_cb callback; /** Callback function */ \ + struct timeout_evt* timeout; /** timeout event handler */ #define NET_CON_STRUCT_SSL \ SSL* ssl; /** SSL handle */ \ diff --git a/src/network/connection.c b/src/network/connection.c index cf8d381..744f248 100644 --- a/src/network/connection.c +++ b/src/network/connection.c @@ -25,7 +25,7 @@ static int handle_openssl_error(struct net_connection* con, int ret) { uhub_assert(con); - int error = SSL_get_error(net_con_get_ssl(con), ret); + int error = SSL_get_error(con->ssl, ret); switch (error) { case SSL_ERROR_ZERO_RETURN: @@ -77,7 +77,7 @@ ssize_t net_con_ssl_accept(struct net_connection* con) { uhub_assert(con); - ssize_t ret = SSL_accept(net_con_get_ssl(con)); + ssize_t ret = SSL_accept(con->ssl); #ifdef NETWORK_DUMP_DEBUG LOG_PROTO("SSL_accept() ret=%d", ret); #endif @@ -96,7 +96,7 @@ ssize_t net_con_ssl_connect(struct net_connection* con) { uhub_assert(con); - ssize_t ret = SSL_connect(net_con_get_ssl(con)); + ssize_t ret = SSL_connect(con->ssl); #ifdef NETWORK_DUMP_DEBUG LOG_PROTO("SSL_connect() ret=%d", ret); #endif @@ -119,14 +119,14 @@ ssize_t net_con_ssl_handshake(struct net_connection* con, enum net_con_ssl_mode if (ssl_mode == net_con_ssl_mode_server) { ssl = SSL_new(ssl_ctx); - SSL_set_fd(ssl, net_con_get_sd(con)); + SSL_set_fd(ssl, con->sd); net_con_set_ssl(con, ssl); return net_con_ssl_accept(con); } else { ssl = SSL_new(SSL_CTX_new(TLSv1_method())); - SSL_set_fd(ssl, net_con_get_sd(con)); + SSL_set_fd(ssl, con->sd); net_con_set_ssl(con, ssl); return net_con_ssl_connect(con); } @@ -136,7 +136,7 @@ ssize_t net_con_ssl_handshake(struct net_connection* con, enum net_con_ssl_mode ssize_t net_con_send(struct net_connection* con, const void* buf, size_t len) { - int ret = net_send(net_con_get_sd(con), buf, len, UHUB_SEND_SIGNAL); + int ret = net_send(con->sd, buf, len, UHUB_SEND_SIGNAL); if (ret == -1) { if (net_error() == EWOULDBLOCK || net_error() == EINTR) @@ -154,7 +154,7 @@ ssize_t net_con_recv(struct net_connection* con, void* buf, size_t len) if (!net_con_is_ssl(con)) { #endif - int ret = net_recv(net_con_get_sd(con), buf, len, 0); + int ret = net_recv(con->sd, buf, len, 0); #ifdef NETWORK_DUMP_DEBUG LOG_PROTO("net_recv: ret=%d", ret); #endif @@ -174,7 +174,7 @@ ssize_t net_con_recv(struct net_connection* con, void* buf, size_t len) } else { - int ret = SSL_read(net_con_get_ssl(con), buf, len); + int ret = SSL_read(con->ssl, buf, len); #ifdef NETWORK_DUMP_DEBUG LOG_PROTO("net_recv: ret=%d", ret); #endif @@ -193,7 +193,7 @@ ssize_t net_con_recv(struct net_connection* con, void* buf, size_t len) ssize_t net_con_peek(struct net_connection* con, void* buf, size_t len) { - int ret = net_recv(net_con_get_sd(con), buf, len, MSG_PEEK); + int ret = net_recv(con->sd, buf, len, MSG_PEEK); if (ret == -1) { if (net_error() == EWOULDBLOCK || net_error() == EINTR) @@ -205,6 +205,39 @@ ssize_t net_con_peek(struct net_connection* con, void* buf, size_t len) return ret; } +#ifdef SSL_SUPPORT +int net_con_is_ssl(struct net_connection* con) +{ + return con->ssl != 0; +} +SSL* net_con_get_ssl(struct net_connection* con) +{ + return con->ssl; +} +void net_con_set_ssl(struct net_connection* con, SSL* ssl) +{ + con->ssl = ssl; +} +#endif /* SSL_SUPPORT */ + +int net_con_get_sd(struct net_connection* con) +{ + return con->sd; +} + +void* net_con_get_ptr(struct net_connection* con) +{ + return con->ptr; +} + +void net_con_callback(struct net_connection* con, int events) +{ + if (!(con->flags & NET_CLEANUP)) + { + LOG_TRACE("net_con_callback(%p, %s%s%s)", con, (events & NET_EVENT_READ ? "R" : ""), (events & NET_EVENT_WRITE ? "W" : ""), events == NET_EVENT_TIMEOUT ? "TIMEOUT" : ""); + con->callback(con, events, con->ptr); + } +} diff --git a/src/network/connection.h b/src/network/connection.h index 7ec602e..3f5fbf9 100644 --- a/src/network/connection.h +++ b/src/network/connection.h @@ -21,6 +21,7 @@ #define HAVE_UHUB_NETWORK_CONNECTION_H #include "uhub.h" +#include "network/common.h" #include "network/backend.h" #define NET_EVENT_TIMEOUT 0x0001 @@ -30,8 +31,14 @@ #define NET_EVENT_CLOSED 0x2000 /* Socket closed */ struct net_connection; + typedef void (*net_connection_cb)(struct net_connection*, int event, void* ptr); +struct net_connection +{ + NET_CON_STRUCT_COMMON +}; + extern int net_con_get_sd(struct net_connection* con); extern void* net_con_get_ptr(struct net_connection* con); @@ -40,6 +47,7 @@ extern void net_con_destroy(struct net_connection*); extern void net_con_initialize(struct net_connection* con, int sd, net_connection_cb callback, const void* ptr, int events); extern void net_con_reinitialize(struct net_connection* con, net_connection_cb callback, const void* ptr, int events); extern void net_con_update(struct net_connection* con, int events); +extern void net_con_callback(struct net_connection* con, int events); /** * Close the connection. diff --git a/src/network/epoll.c b/src/network/epoll.c index 4df8c0f..b58f680 100644 --- a/src/network/epoll.c +++ b/src/network/epoll.c @@ -27,18 +27,10 @@ #define EPOLL_EVBUFFER 512 -struct net_connection +struct net_connection_epoll { - int sd; - uint32_t flags; - net_connection_cb callback; - void* ptr; - struct epoll_event ev; - struct timeout_evt* timeout; -#ifdef SSL_SUPPORT - SSL* ssl; - size_t write_len; /** Length of last SSL_write(), only used if flags is NET_WANT_SSL_READ. */ -#endif + NET_CON_STRUCT_COMMON + struct epoll_event ev; }; struct net_backend @@ -46,7 +38,7 @@ struct net_backend int epfd; size_t num; size_t max; - struct net_connection** conns; + struct net_connection_epoll** conns; struct epoll_event events[EPOLL_EVBUFFER]; time_t now; struct timeout_queue timeout_queue; @@ -54,7 +46,7 @@ struct net_backend static struct net_backend* g_backend = 0; -static void net_con_print(const char* prefix, struct net_connection* con) +static void net_con_print(const char* prefix, struct net_connection_epoll* con) { char buf[512]; int off = snprintf(buf, 512, "%s: net_connection={ sd=%d, flags=%u, callback=%p, ptr=%p, ev={ events=%s%s, data.ptr=%p }", @@ -87,7 +79,7 @@ int net_backend_initialize() g_backend->num = 0; g_backend->max = max; - g_backend->conns = hub_malloc_zero(sizeof(struct net_connection*) * max); + g_backend->conns = hub_malloc_zero(sizeof(struct net_connection_epoll*) * max); memset(g_backend->events, 0, sizeof(g_backend->events)); g_backend->now = time(0); @@ -121,19 +113,23 @@ int net_backend_process() for (n = 0; n < res; n++) { - struct net_connection* con = (struct net_connection*) g_backend->events[n].data.ptr; + struct net_connection_epoll* con = (struct net_connection_epoll*) g_backend->events[n].data.ptr; int ev = 0; if (g_backend->events[n].events & EPOLLIN) ev |= NET_EVENT_READ; if (g_backend->events[n].events & EPOLLOUT) ev |= NET_EVENT_WRITE; - con->callback(con, ev, con->ptr); + net_con_callback((struct net_connection*) con, ev); } return 1; } +struct timeout_queue* net_backend_get_timeout_queue() +{ + return &g_backend->timeout_queue; +} struct net_connection* net_con_create() { - struct net_connection* con = (struct net_connection*) hub_malloc_zero(sizeof(struct net_connection)); + struct net_connection* con = (struct net_connection*) hub_malloc_zero(sizeof(struct net_connection_epoll)); con->sd = -1; return con; } @@ -143,8 +139,9 @@ void net_con_destroy(struct net_connection* con) hub_free(con); } -void net_con_initialize(struct net_connection* con, int sd, net_connection_cb callback, const void* ptr, int events) +void net_con_initialize(struct net_connection* con_, int sd, net_connection_cb callback, const void* ptr, int events) { + struct net_connection_epoll* con = (struct net_connection_epoll*) con_; con->sd = sd; con->flags = NET_INITIALIZED; con->callback = callback; @@ -176,10 +173,11 @@ void net_con_reinitialize(struct net_connection* con, net_connection_cb callback net_con_update(con, events); } -void net_con_update(struct net_connection* con, int events) +void net_con_update(struct net_connection* con_, int events) { + struct net_connection_epoll* con = (struct net_connection_epoll*) con_; con->ev.events = 0; - if (events & NET_EVENT_READ) con->ev.events |= EPOLLIN; + if (events & NET_EVENT_READ) con->ev.events |= EPOLLIN; if (events & NET_EVENT_WRITE) con->ev.events |= EPOLLOUT; #ifdef SSL_SUPPORT @@ -211,8 +209,9 @@ void net_con_update(struct net_connection* con, int events) net_con_print("MOD", con); } -int net_con_close(struct net_connection* con) +int net_con_close(struct net_connection* con_) { + struct net_connection_epoll* con = (struct net_connection_epoll*) con_; if (!(con->flags & NET_INITIALIZED)) return 0; @@ -239,68 +238,4 @@ int net_con_close(struct net_connection* con) return 0; } -#ifdef SSL_SUPPORT -int net_con_is_ssl(struct net_connection* con) -{ - - return con->ssl != 0; -} - -SSL* net_con_get_ssl(struct net_connection* con) -{ - return con->ssl; -} - -void net_con_set_ssl(struct net_connection* con, SSL* ssl) -{ - con->ssl = ssl; -} -#endif - -int net_con_get_sd(struct net_connection* con) -{ - return con->sd; -} - -void* net_con_get_ptr(struct net_connection* con) -{ - return con->ptr; -} - - -void timeout_evt_initialize(struct timeout_evt*, timeout_evt_cb, void* ptr); -void timeout_evt_reset(struct timeout_evt*); -int timeout_evt_is_scheduled(struct timeout_evt*); - -static void timeout_callback(struct timeout_evt* evt) -{ - struct net_connection* con = (struct net_connection*) evt->ptr; - con->callback(con, NET_EVENT_TIMEOUT, con->ptr); -} - - -void net_con_set_timeout(struct net_connection* con, int seconds) -{ - if (!con->timeout) - { - con->timeout = hub_malloc_zero(sizeof(struct timeout_evt)); - timeout_evt_initialize(con->timeout, timeout_callback, con); - timeout_queue_insert(&g_backend->timeout_queue, con->timeout, seconds); - } - else - { - timeout_queue_reschedule(&g_backend->timeout_queue, con->timeout, seconds); - } -} - -void net_con_clear_timeout(struct net_connection* con) -{ - if (con->timeout && timeout_evt_is_scheduled(con->timeout)) - { - timeout_queue_remove(&g_backend->timeout_queue, con->timeout); - hub_free(con->timeout); - con->timeout = 0; - } -} - #endif /* USE_EPOLL */ diff --git a/src/network/libevent.c b/src/network/libevent.c deleted file mode 100644 index 4d27015..0000000 --- a/src/network/libevent.c +++ /dev/null @@ -1,399 +0,0 @@ -/* - * uhub - A tiny ADC p2p connection hub - * Copyright (C) 2007-2009, Jan Vidar Krey - * - * 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 . - * - */ - -#ifdef USE_LIBEVENT - -struct net_connection -{ - NET_CON_STRUCT_COMMON - struct event event; /** libevent struct for read/write events */ - struct event timeout; /** Used for internal timeout handling */ -}; - -struct net_timer -{ - unsigned int initialized; - struct event timeout; - net_timeout_cb callback; - void* ptr; -}; - -int net_con_get_sd(struct net_connection* con) -{ - return con->sd; -} - -void* net_con_get_ptr(struct net_connection* con) -{ - return con->ptr; -} - -struct net_connection* net_con_create() -{ - struct net_connection* con = (struct net_connection*) hub_malloc(sizeof(struct net_connection)); - return con; -} - -static inline int net_con_flag_get(struct net_connection* con, unsigned int flag) -{ - return con->flags & flag; -} - -static inline void net_con_flag_set(struct net_connection* con, unsigned int flag) -{ - con->flags |= flag; -} - -static inline void net_con_flag_unset(struct net_connection* con, unsigned int flag) -{ - con->flags &= ~flag; -} - -void net_con_destroy(struct net_connection* con) -{ - hub_free(con); -} - -static inline int net_con_convert_to_libevent_mask(int ev) -{ - int events = 0; - if (ev & NET_EVENT_READ) events |= EV_READ; - if (ev & NET_EVENT_WRITE) events |= EV_WRITE; - return events; -} - -static inline int net_con_convert_from_libevent_mask(int ev) -{ - int events = 0; - if (ev & EV_TIMEOUT) events |= NET_EVENT_TIMEOUT; - if (ev & EV_READ) events |= NET_EVENT_READ; - if (ev & EV_WRITE) events |= NET_EVENT_WRITE; - return events; -} - -static void net_con_event(int fd, short ev, void *arg); - - -int net_con_close(struct net_connection* con) -{ - uhub_assert(con); - - con->ptr = 0; - - if (net_con_flag_get(con, NET_CLEANUP)) - return 0; - - if (net_con_flag_get(con, NET_PROCESSING_BUSY)) - { - net_con_flag_set(con, NET_CLEANUP); - return 0; - } - - net_con_after_close(con); - return 1; -} - -static void net_con_set(struct net_connection* con) -{ - uhub_assert(con); - - int ev = 0; - if (net_con_flag_get(con, NET_WANT_READ | NET_WANT_SSL_READ)) ev |= EV_READ; - if (net_con_flag_get(con, NET_WANT_WRITE | NET_WANT_SSL_WRITE)) ev |= EV_WRITE; - - if (net_con_flag_get(con, NET_EVENT_SET) != 0) - { - event_del(&con->event); - } - net_con_flag_set(con, NET_EVENT_SET); - - LOG_MEMORY("SET: set+add: CON={ %p, %p, %d, %d}", con, &con->event, con->sd, ev); - event_set(&con->event, con->sd, ev, net_con_event, con); - event_add(&con->event, 0); - - net_con_flag_set(con, NET_INITIALIZED); -} - -static void net_con_after_close(struct net_connection* con) -{ - if (net_con_flag_get(con, NET_INITIALIZED)) - { - LOG_MEMORY("DEL: close: CON={ %p, %p, %d, %d}", con, &con->event, con->sd, -1); - net_con_flag_unset(con, NET_EVENT_SET); - - event_del(&con->event); - net_con_flag_unset(con, NET_INITIALIZED); - } - - net_con_clear_timeout(con); - net_close(con->sd); - con->sd = -1; - - hub_free(con); -} - -void net_con_initialize(struct net_connection* con, int sd, net_connection_cb callback, const void* ptr, int ev) -{ - uhub_assert(con); - - int events = net_con_convert_to_libevent_mask(ev); - if (ev & NET_EVENT_READ) net_con_flag_set(con, NET_WANT_READ); - if (ev & NET_EVENT_WRITE) net_con_flag_set(con, NET_WANT_WRITE); - - con->sd = sd; - con->flags = 0; - con->ptr = (void*) ptr; - con->callback = callback; - con->last_send = time(0); - con->last_recv = con->last_send; - - if (ev) - { - uhub_assert(net_con_flag_get(con, NET_EVENT_SET) == 0); - net_con_flag_set(con, NET_EVENT_SET); - - LOG_MEMORY("SET: init: CON={ %p, %p, %d, %d}", con, &con->event, con->sd, ev); - event_set(&con->event, con->sd, events, net_con_event, con); - event_add(&con->event, 0); - net_con_flag_set(con, NET_INITIALIZED); - } - - net_set_nonblocking(sd, 1); - net_set_nosigpipe(sd, 1); - -#ifdef SSL_SUPPORT - con->ssl = NULL; - con->write_len = 0; -#endif -} - -void net_con_reinitialize(struct net_connection* con, net_connection_cb callback, const void* ptr, int events) -{ - uhub_assert(con); - con->callback = callback; - con->ptr = (void*) ptr; - net_con_update(con, events); -} - -void net_con_update(struct net_connection* con, int ev) -{ - uhub_assert(con); - - if (ev & NET_EVENT_READ) - net_con_flag_set(con, NET_EVENT_READ); - else - net_con_flag_unset(con, NET_EVENT_READ); - - if (ev & NET_EVENT_WRITE) - net_con_flag_set(con, NET_EVENT_WRITE); - else - net_con_flag_unset(con, NET_EVENT_WRITE); - - if (!net_con_flag_get(con, NET_PROCESSING_BUSY)) - { - net_con_set(con); - } -} - -#define CALLBACK(CON, EVENTS) \ - if (CON->callback) \ - CON->callback(con, EVENTS, CON->ptr); - -static void net_con_event(int fd, short ev, void *arg) -{ - struct net_connection* con = (struct net_connection*) arg; - int events = net_con_convert_from_libevent_mask(ev); - - if (!net_con_flag_get(con, NET_INITIALIZED)) - { - return; - } - - if (net_con_flag_get(con, NET_CLEANUP)) - { - net_con_after_close(con); - return; - } - - net_con_flag_set(con, NET_PROCESSING_BUSY); - -// uhub_assert(net_con_flag_get(con, NET_EVENT_SET) != 0); - net_con_flag_unset(con, NET_EVENT_SET); - - LOG_MEMORY("EVT: process: CON={ %p, %p, %d, %d}", con, &con->event, con->sd, (int) ev); - -#ifdef SSL_SUPPORT - if (!con->ssl) - { -#endif - CALLBACK(con, events); -#ifdef SSL_SUPPORT - } - else - { -#ifdef NETWORK_DUMP_DEBUG - LOG_PROTO("net_con_event: events=%d, con=%p", ev, con); -#endif - if (ev & (EV_READ | EV_WRITE)) - { - if (net_con_flag_get(con, NET_WANT_SSL_ACCEPT)) - { - if (net_con_ssl_accept(con) < 0) - CALLBACK(con, NET_EVENT_SOCKERROR); - } - else if (net_con_flag_get(con, NET_WANT_SSL_CONNECT)) - { - if (net_con_ssl_connect(con) < 0) - CALLBACK(con, NET_EVENT_SOCKERROR); - } - else if (ev == EV_READ && net_con_flag_get(con, NET_WANT_SSL_READ)) - { - CALLBACK(con, NET_EVENT_WRITE); - } - else if (ev == EV_WRITE && net_con_flag_get(con, NET_WANT_SSL_WRITE)) - { - CALLBACK(con, events & NET_EVENT_READ); - } - else - { - CALLBACK(con, events); - } - } - else - { - CALLBACK(con, events); - } - } -#endif - net_con_flag_unset(con, NET_PROCESSING_BUSY); - - if (net_con_flag_get(con, NET_CLEANUP)) - { - net_con_after_close(con); - } - else - { - net_con_set(con); - } -} - - -static void net_timer_event(int fd, short ev, void *arg) -{ - struct net_timer* timer = (struct net_timer*) arg; - timer->callback(timer, timer->ptr); -} - -void net_timer_initialize(struct net_timer* timer, net_timeout_cb callback, void* ptr) -{ - timer->initialized = 0; - timer->callback = callback; - timer->ptr = ptr; -} - -void net_timer_reset(struct net_timer* timer, int seconds) -{ - struct timeval timeout = { seconds, 0 }; - if (timer->initialized) - { - evtimer_del(&timer->timeout); - timer->initialized = 0; - } - evtimer_set(&timer->timeout, net_timer_event, timer); - evtimer_add(&timer->timeout, &timeout); -} - -void net_timer_shutdown(struct net_timer* timer) -{ - if (timer->initialized) - { - evtimer_del(&timer->timeout); - timer->initialized = 0; - } - timer->callback = 0; - timer->ptr = 0; -} - - -void net_con_set_timeout(struct net_connection* con, int seconds) -{ - uhub_assert(con); - - struct timeval timeout = { seconds, 0 }; - net_con_clear_timeout(con); - - evtimer_set(&con->timeout, net_con_event, con); - evtimer_add(&con->timeout, &timeout); - net_con_flag_set(con, NET_TIMER_ENABLED); -} - -void net_con_clear_timeout(struct net_connection* con) -{ - uhub_assert(con); - - if (net_con_flag_get(con, NET_TIMER_ENABLED)) - { - evtimer_del(&con->timeout); - net_con_flag_unset(con, NET_TIMER_ENABLED); - } -} - -static struct event_base g_evbase = 0; - -/** - * Initialize the network backend. - * Returns 1 on success, or 0 on failure. - */ -int net_backend_initialize() -{ - g_evbase = event_init(); - if (!g_evbase) - { - LOG_ERROR("Unable to initialize libevent."); - return 0; - } - LOG_DEBUG("Using libevent %s, backend: %s", event_get_version(), event_get_method()); - return 1; -} - -/** - * Shutdown the network connection backend. - */ -void net_backend_shutdown() -{ - event_base_free(g_evbase); -} - -/** - * Process the network backend. - */ -int net_backend_process() -{ - int ret = event_base_loop(g_evbase, EVLOOP_ONCE); - if (ret != 0) - { - LOG_DEBUG("event_base_loop returned: %d", (int) ret); - } - if (ret < 0) - return 0; - return 1; -} - - -#endif /* USE_LIBEVENT */ diff --git a/src/network/select.c b/src/network/select.c new file mode 100644 index 0000000..989ba39 --- /dev/null +++ b/src/network/select.c @@ -0,0 +1,208 @@ +/* + * uhub - A tiny ADC p2p connection hub + * Copyright (C) 2007-2010, Jan Vidar Krey + * + * 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 . + * + */ + +#include "uhub.h" + +#ifdef USE_SELECT + +#include "network/connection.h" +#include "network/common.h" +#include "network/backend.h" + +struct net_connection_select +{ + NET_CON_STRUCT_COMMON +}; + +struct net_backend +{ + size_t num; + size_t max; + struct net_connection_select** conns; + fd_set rfds; + fd_set wfds; + time_t now; + struct timeout_queue timeout_queue; +}; + +static struct net_backend* g_backend = 0; + +static void net_con_print(const char* prefix, struct net_connection_select* con) +{ + char buf[512]; + int off = snprintf(buf, 512, "%s: net_connection={ sd=%d, flags=%u, callback=%p, ptr=%p, events=%s%s", + prefix, con->sd, con->flags, con->callback, con->ptr, (con->flags & NET_EVENT_READ ? "R" : ""),(con->flags & NET_EVENT_WRITE ? "W" : "")); + if (con->timeout) + { + sprintf(buf + off, ", timeout={ %d seconds left }", (int) (con->timeout->timestamp - g_backend->now)); + } + else + { + sprintf(buf + off, ", timeout=NULL"); + } + LOG_TRACE(buf); +} + +/** + * Initialize the network backend. + * Returns 1 on success, or 0 on failure. + */ +int net_backend_initialize() +{ + size_t max = net_get_max_sockets(); + g_backend = hub_malloc(sizeof(struct net_backend)); + g_backend->num = 0; + g_backend->max = max; + g_backend->conns = hub_malloc_zero(sizeof(struct net_connection_select*) * max); + FD_ZERO(&g_backend->rfds); + FD_ZERO(&g_backend->wfds); + g_backend->now = time(0); + timeout_queue_initialize(&g_backend->timeout_queue, g_backend->now, 600); /* look max 10 minutes into the future. */ + return 1; +} + +/** + * Shutdown the network connection backend. + */ +void net_backend_shutdown() +{ + hub_free(g_backend->conns); + hub_free(g_backend); +} + +/** + * Process the network backend. + */ +int net_backend_process() +{ + int n, found, maxfd; + struct timeval tval = { 1, 0 }; + FD_ZERO(&g_backend->rfds); + FD_ZERO(&g_backend->wfds); + for (n = 0, found = 0; found < g_backend->num && n < g_backend->max; n++) + { + struct net_connection_select* con = g_backend->conns[n]; + if (con) + { + if (con->flags & NET_EVENT_READ) FD_SET(con->sd, &g_backend->rfds); + if (con->flags & NET_EVENT_WRITE) FD_SET(con->sd, &g_backend->wfds); + found++; + maxfd = con->sd; + } + } + + int res = select(maxfd+1, &g_backend->rfds, &g_backend->wfds, 0, &tval); + if (res == -1) + { + LOG_WARN("select returned -1"); + return 0; + } + + for (n = 0, found = 0; found < res && n < (maxfd+1); n++) + { + struct net_connection_select* con = g_backend->conns[n]; + if (con) + { + int ev = 0; + if (FD_ISSET(con->sd, &g_backend->rfds)) ev |= NET_EVENT_READ; + if (FD_ISSET(con->sd, &g_backend->wfds)) ev |= NET_EVENT_WRITE; + + if (ev) + { + net_con_callback((struct net_connection*) con, ev); + found++; + } + } + } + return 1; +} + +struct timeout_queue* net_backend_get_timeout_queue() +{ + return &g_backend->timeout_queue; +} + +struct net_connection* net_con_create() +{ + struct net_connection* con = (struct net_connection*) hub_malloc_zero(sizeof(struct net_connection_select)); + con->sd = -1; + return con; +} + +void net_con_destroy(struct net_connection* con) +{ + hub_free(con); +} + +void net_con_initialize(struct net_connection* con_, int sd, net_connection_cb callback, const void* ptr, int events) +{ + struct net_connection_select* con = (struct net_connection_select*) con_; + con->sd = sd; + con->flags = NET_INITIALIZED; + con->flags |= events; + con->callback = callback; + con->ptr = (void*) ptr; + + net_set_nonblocking(con->sd, 1); + net_set_nosigpipe(con->sd, 1); + + g_backend->conns[sd] = con; + g_backend->num++; + net_con_print("ADD", con); +} + +void net_con_reinitialize(struct net_connection* con, net_connection_cb callback, const void* ptr, int events) +{ + con->callback = callback; + con->ptr = (void*) ptr; + net_con_update(con, events); +} + +void net_con_update(struct net_connection* con, int events) +{ + con->flags = NET_INITIALIZED; + con->flags |= events; + net_con_print("MOD", (struct net_connection_select*) con); +} + +int net_con_close(struct net_connection* con) +{ + if (!(con->flags & NET_INITIALIZED)) + return 0; + + con->flags &= ~NET_INITIALIZED; + + if (con->sd != -1) + { + g_backend->conns[con->sd] = 0; + g_backend->num--; + } + + if (timeout_evt_is_scheduled(con->timeout)) + { + timeout_queue_remove(&g_backend->timeout_queue, con->timeout); + hub_free(con->timeout); + con->timeout = 0; + } + + net_con_print("DEL", (struct net_connection_select*) con); + return 0; +} + +#endif /* USE_SELECT */ diff --git a/src/network/timer.c b/src/network/timer.c new file mode 100644 index 0000000..9400cb7 --- /dev/null +++ b/src/network/timer.c @@ -0,0 +1,50 @@ +/* + * uhub - A tiny ADC p2p connection hub + * Copyright (C) 2007-2010, Jan Vidar Krey + * + * 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 . + * + */ + +#include "uhub.h" +#include "network/connection.h" + +static void timeout_callback(struct timeout_evt* evt) +{ + net_con_callback((struct net_connection*) evt->ptr, NET_EVENT_TIMEOUT); +} + +void net_con_set_timeout(struct net_connection* con, int seconds) +{ + if (!con->timeout) + { + con->timeout = hub_malloc_zero(sizeof(struct timeout_evt)); + timeout_evt_initialize(con->timeout, timeout_callback, con); + timeout_queue_insert(net_backend_get_timeout_queue(), con->timeout, seconds); + } + else + { + timeout_queue_reschedule(net_backend_get_timeout_queue(), con->timeout, seconds); + } +} + +void net_con_clear_timeout(struct net_connection* con) +{ + if (timeout_evt_is_scheduled(con->timeout)) + { + timeout_queue_remove(net_backend_get_timeout_queue(), con->timeout); + hub_free(con->timeout); + con->timeout = 0; + } +} diff --git a/src/system.h b/src/system.h index 2af2ff5..affc91b 100644 --- a/src/system.h +++ b/src/system.h @@ -102,13 +102,12 @@ #define uhub_assert assert -#ifdef USE_LIBEVENT -#include -#else #ifdef __linux__ #define USE_EPOLL #include -#endif +#else +#define USE_SELECT +#include #endif #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__sun__) diff --git a/src/tools/adcrush.c b/src/tools/adcrush.c index eb72450..e54f502 100644 --- a/src/tools/adcrush.c +++ b/src/tools/adcrush.c @@ -330,7 +330,7 @@ void runloop(size_t clients) while (running) { - event_base_loop(net_get_evbase(), EVLOOP_ONCE); + net_backend_process(); } for (n = 0; n < clients; n++) @@ -413,63 +413,17 @@ void parse_command_line(int argc, char** argv) } } -#ifndef WIN32 -static void handle_signal(int signal, short events, void* arg) -{ - switch (signal) - { - case SIGINT: - case SIGTERM: - running = 0; - break; - default: - break; - } -} - -static struct event signal_events[10]; -static int signals[] = -{ - SIGINT, /* Interrupt the application */ - SIGTERM, /* Terminate the application */ - 0 -}; - -void setup_signal_handlers() -{ - int i = 0; - for (i = 0; signals[i]; i++) - { - signal_set(&signal_events[i], signals[i], handle_signal, NULL); - signal_add(&signal_events[i], NULL); - } -} - -void shutdown_signal_handlers() -{ - int i = 0; - for (i = 0; signals[i]; i++) - { - signal_del(&signal_events[i]); - } -} -#endif /* WIN32 */ - - int main(int argc, char** argv) { parse_command_line(argc, argv); net_initialize(); - setup_signal_handlers(); hub_log_initialize(NULL, 0); hub_set_log_verbosity(1000); runloop(cfg_clients); - shutdown_signal_handlers(); net_destroy(); - return 0; } diff --git a/src/tools/admin.c b/src/tools/admin.c index 113e770..225cbb2 100644 --- a/src/tools/admin.c +++ b/src/tools/admin.c @@ -63,6 +63,7 @@ static int handle(struct ADC_client* client, enum ADC_client_callback_type type, return 1; } +static int running = 1; int main(int argc, char** argv) { @@ -79,7 +80,10 @@ int main(int argc, char** argv) ADC_client_set_callback(&client, handle); ADC_client_connect(&client, argv[1]); - event_dispatch(); + while (running) + { + net_backend_process(); + } ADC_client_destroy(&client); net_destroy(); diff --git a/src/util/timeout.c b/src/util/timeout.c index 1009e70..b2daaa0 100644 --- a/src/util/timeout.c +++ b/src/util/timeout.c @@ -99,7 +99,7 @@ void timeout_queue_remove(struct timeout_queue* t, struct timeout_evt* evt) size_t pos = (evt->timestamp % t->max); struct timeout_evt* first = t->events[pos]; - if (!first) + if (!first || !evt) return; if (first == evt)