Compile multiple network backends into the binary and choose which one to use at runtime.
This makes it possible to share more code between the backends and also work around bugs of certain backends on some (versions of) operating systems.
This commit is contained in:
@@ -21,6 +21,9 @@
|
||||
|
||||
#include "network/connection.h"
|
||||
|
||||
struct net_backend;
|
||||
struct net_connection;
|
||||
|
||||
struct net_cleanup_handler
|
||||
{
|
||||
size_t num;
|
||||
@@ -28,6 +31,157 @@ struct net_cleanup_handler
|
||||
struct net_connection** queue;
|
||||
};
|
||||
|
||||
struct net_backend
|
||||
{
|
||||
struct net_backend_common common;
|
||||
time_t now; /* the time now (used for timeout handling) */
|
||||
struct timeout_queue timeout_queue; /* used for timeout handling */
|
||||
struct net_cleanup_handler* cleaner; /* handler to cleanup connections at a safe point */
|
||||
struct net_backend_handler handler; /* backend event handler */
|
||||
struct net_backend* data; /* backend specific data */
|
||||
};
|
||||
|
||||
static struct net_backend* g_backend;
|
||||
|
||||
|
||||
#ifdef USE_EPOLL
|
||||
extern struct net_backend* net_backend_init_epoll(struct net_backend_handler*, struct net_backend_common*);
|
||||
#endif
|
||||
|
||||
#ifdef USE_KQUEUE
|
||||
extern struct net_backend* net_backend_init_kqueue(struct net_backend_handler*, struct net_backend_common*);
|
||||
#endif
|
||||
|
||||
#ifdef USE_SELECT
|
||||
extern struct net_backend* net_backend_init_select(struct net_backend_handler*, struct net_backend_common*);
|
||||
#endif
|
||||
|
||||
static net_backend_init_t net_backend_init_funcs[] = {
|
||||
#ifdef USE_EPOLL
|
||||
net_backend_init_epoll,
|
||||
#endif
|
||||
#ifdef USE_KQUEUE
|
||||
net_backend_init_kqueue,
|
||||
#endif
|
||||
#ifdef USE_SELECT
|
||||
net_backend_init_select,
|
||||
#endif
|
||||
0
|
||||
};
|
||||
|
||||
int net_backend_init()
|
||||
{
|
||||
size_t n;
|
||||
g_backend = hub_malloc_zero(sizeof(struct net_backend));
|
||||
g_backend->common.num = 0;
|
||||
g_backend->common.max = net_get_max_sockets();
|
||||
g_backend->now = time(0);
|
||||
timeout_queue_initialize(&g_backend->timeout_queue, g_backend->now, 600); /* FIXME: max 600 secs! */
|
||||
g_backend->cleaner = net_cleanup_initialize(g_backend->common.max);
|
||||
|
||||
for (n = 0; n < sizeof(net_backend_init_funcs); n++)
|
||||
{
|
||||
if (!net_backend_init_funcs[n])
|
||||
break;
|
||||
|
||||
g_backend->data = net_backend_init_funcs[n](&g_backend->handler, &g_backend->common);
|
||||
if (g_backend->data)
|
||||
{
|
||||
LOG_DEBUG("Initialized %s network backend.", g_backend->handler.backend_name());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
LOG_FATAL("Unable to find a suitable network backend");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void net_backend_shutdown()
|
||||
{
|
||||
g_backend->handler.backend_shutdown(g_backend->data);
|
||||
timeout_queue_shutdown(&g_backend->timeout_queue);
|
||||
net_cleanup_shutdown(g_backend->cleaner);
|
||||
hub_free(g_backend);
|
||||
g_backend = 0;
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
g_backend->handler.con_mod(g_backend->data, con, events);
|
||||
}
|
||||
|
||||
struct net_connection* net_con_create()
|
||||
{
|
||||
return g_backend->handler.con_create(g_backend->data);
|
||||
}
|
||||
|
||||
struct timeout_queue* net_backend_get_timeout_queue()
|
||||
{
|
||||
if (!g_backend)
|
||||
return 0;
|
||||
return &g_backend->timeout_queue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the network backend.
|
||||
*/
|
||||
int net_backend_process()
|
||||
{
|
||||
int res;
|
||||
size_t secs = timeout_queue_get_next_timeout(&g_backend->timeout_queue, g_backend->now);
|
||||
|
||||
res = g_backend->handler.backend_poll(g_backend->data, secs * 1000);
|
||||
|
||||
g_backend->now = time(0);
|
||||
timeout_queue_process(&g_backend->timeout_queue, g_backend->now);
|
||||
|
||||
if (res == -1)
|
||||
{
|
||||
LOG_WARN("backend error.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
g_backend->handler.backend_process(g_backend->data, res);
|
||||
|
||||
net_cleanup_process(g_backend->cleaner);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void net_con_initialize(struct net_connection* con, int sd, net_connection_cb callback, const void* ptr, int events)
|
||||
{
|
||||
g_backend->handler.con_init(g_backend->data, con, sd, callback, ptr);
|
||||
|
||||
net_set_nonblocking(con->sd, 1);
|
||||
net_set_nosigpipe(con->sd, 1);
|
||||
|
||||
g_backend->handler.con_add(g_backend->data, con, events);
|
||||
g_backend->common.num++;
|
||||
}
|
||||
|
||||
void net_con_close(struct net_connection* con)
|
||||
{
|
||||
if (con->flags & NET_CLEANUP)
|
||||
return;
|
||||
|
||||
g_backend->common.num--;
|
||||
net_con_clear_timeout(con);
|
||||
|
||||
g_backend->handler.con_del(g_backend->data, con);
|
||||
|
||||
net_close(con->sd);
|
||||
con->sd = -1;
|
||||
|
||||
net_cleanup_delayed_free(g_backend->cleaner, con);
|
||||
}
|
||||
|
||||
struct net_cleanup_handler* net_cleanup_initialize(size_t max)
|
||||
{
|
||||
struct net_cleanup_handler* handler = (struct net_cleanup_handler*) hub_malloc(sizeof(struct net_cleanup_handler));
|
||||
|
||||
Reference in New Issue
Block a user