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:
@@ -30,113 +30,67 @@ struct net_connection_select
|
||||
NET_CON_STRUCT_COMMON
|
||||
};
|
||||
|
||||
struct net_backend
|
||||
struct net_backend_select
|
||||
{
|
||||
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;
|
||||
struct net_cleanup_handler* cleaner;
|
||||
int maxfd;
|
||||
struct net_backend_common* common;
|
||||
};
|
||||
|
||||
static struct net_backend* g_backend = 0;
|
||||
static void net_backend_set_handlers(struct net_backend_handler* handler);
|
||||
|
||||
static void net_con_print(const char* prefix, struct net_connection_select* con)
|
||||
const char* net_backend_name_select()
|
||||
{
|
||||
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);
|
||||
return "select";
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the network backend.
|
||||
* Returns 1 on success, or 0 on failure.
|
||||
*/
|
||||
int net_backend_initialize()
|
||||
int net_backend_poll_select(struct net_backend* data, int ms)
|
||||
{
|
||||
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. */
|
||||
g_backend->cleaner = net_cleanup_initialize(max);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown the network connection backend.
|
||||
*/
|
||||
void net_backend_shutdown()
|
||||
{
|
||||
timeout_queue_shutdown(&g_backend->timeout_queue);
|
||||
net_cleanup_shutdown(g_backend->cleaner);
|
||||
hub_free(g_backend->conns);
|
||||
hub_free(g_backend);
|
||||
g_backend = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the network backend.
|
||||
*/
|
||||
int net_backend_process()
|
||||
{
|
||||
int n, found, maxfd, res;
|
||||
int found, res, n;
|
||||
struct timeval tval;
|
||||
size_t secs;
|
||||
struct net_backend_select* backend = (struct net_backend_select*) data;
|
||||
|
||||
FD_ZERO(&g_backend->rfds);
|
||||
FD_ZERO(&g_backend->wfds);
|
||||
tval.tv_sec = ms / 1000;
|
||||
tval.tv_usec = ((ms % 1000) * 1000); // FIXME: correct?
|
||||
|
||||
secs = timeout_queue_get_next_timeout(&g_backend->timeout_queue, g_backend->now);
|
||||
tval.tv_sec = secs;
|
||||
tval.tv_usec = 0;
|
||||
FD_ZERO(&backend->rfds);
|
||||
FD_ZERO(&backend->wfds);
|
||||
|
||||
for (n = 0, found = 0; found < g_backend->num && n < g_backend->max; n++)
|
||||
backend->maxfd = -1;
|
||||
for (n = 0, found = 0; found < backend->common->num && n < backend->common->max; n++)
|
||||
{
|
||||
struct net_connection_select* con = g_backend->conns[n];
|
||||
struct net_connection_select* con = 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);
|
||||
if (con->flags & NET_EVENT_READ) FD_SET(con->sd, &backend->rfds);
|
||||
if (con->flags & NET_EVENT_WRITE) FD_SET(con->sd, &backend->wfds);
|
||||
found++;
|
||||
maxfd = con->sd;
|
||||
backend->maxfd = con->sd;
|
||||
}
|
||||
}
|
||||
backend->maxfd++;
|
||||
|
||||
res = select(maxfd+1, &g_backend->rfds, &g_backend->wfds, 0, &tval);
|
||||
g_backend->now = time(0);
|
||||
timeout_queue_process(&g_backend->timeout_queue, g_backend->now);
|
||||
res = select(backend->maxfd, &backend->rfds, &backend->wfds, 0, &tval);
|
||||
|
||||
if (res == -1)
|
||||
{
|
||||
LOG_WARN("select returned -1");
|
||||
if (res == -1 && errno == EINTR)
|
||||
return 0;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
for (n = 0, found = 0; found < res && n < (maxfd+1); n++)
|
||||
void net_backend_process_select(struct net_backend* data, int res)
|
||||
{
|
||||
int n, found;
|
||||
struct net_backend_select* backend = (struct net_backend_select*) data;
|
||||
for (n = 0, found = 0; found < res && n < backend->maxfd; n++)
|
||||
{
|
||||
struct net_connection_select* con = g_backend->conns[n];
|
||||
struct net_connection_select* con = 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 (FD_ISSET(con->sd, &backend->rfds)) ev |= NET_EVENT_READ;
|
||||
if (FD_ISSET(con->sd, &backend->wfds)) ev |= NET_EVENT_WRITE;
|
||||
|
||||
if (ev)
|
||||
{
|
||||
@@ -145,78 +99,75 @@ int net_backend_process()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
net_cleanup_process(g_backend->cleaner);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct timeout_queue* net_backend_get_timeout_queue()
|
||||
{
|
||||
if (!g_backend)
|
||||
return 0;
|
||||
|
||||
return &g_backend->timeout_queue;
|
||||
}
|
||||
|
||||
struct net_connection* net_con_create()
|
||||
struct net_connection* net_con_create_select(struct net_backend* data)
|
||||
{
|
||||
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)
|
||||
void net_con_initialize_select(struct net_backend* data, struct net_connection* con_, int sd, net_connection_cb callback, const void* ptr)
|
||||
{
|
||||
struct net_connection_select* con = (struct net_connection_select*) con_;
|
||||
con->sd = sd;
|
||||
con->flags = events;
|
||||
con->flags = 0;
|
||||
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)
|
||||
void net_con_backend_add_select(struct net_backend* data, struct net_connection* con, int events)
|
||||
{
|
||||
con->callback = callback;
|
||||
con->ptr = (void*) ptr;
|
||||
net_con_update(con, events);
|
||||
struct net_backend_select* backend = (struct net_backend_select*) data;
|
||||
backend->conns[con->sd] = (struct net_connection_select*) con;
|
||||
}
|
||||
|
||||
void net_con_update(struct net_connection* con, int events)
|
||||
void net_con_backend_mod_select(struct net_backend* data, struct net_connection* con, int events)
|
||||
{
|
||||
con->flags = events;
|
||||
net_con_print("MOD", (struct net_connection_select*) con);
|
||||
con->flags |= (events & (NET_EVENT_READ | NET_EVENT_WRITE));;
|
||||
}
|
||||
|
||||
void net_con_close(struct net_connection* con)
|
||||
void net_con_backend_del_select(struct net_backend* data, struct net_connection* con)
|
||||
{
|
||||
if (con->flags & NET_CLEANUP)
|
||||
return;
|
||||
struct net_backend_select* backend = (struct net_backend_select*) data;
|
||||
backend->conns[con->sd] = 0;
|
||||
}
|
||||
|
||||
if (con->sd != -1)
|
||||
{
|
||||
g_backend->conns[con->sd] = 0;
|
||||
g_backend->num--;
|
||||
}
|
||||
void net_backend_shutdown_select(struct net_backend* data)
|
||||
{
|
||||
struct net_backend_select* backend = (struct net_backend_select*) data;
|
||||
hub_free(backend->conns);
|
||||
hub_free(backend);
|
||||
}
|
||||
|
||||
net_con_clear_timeout(con);
|
||||
struct net_backend* net_backend_init_select(struct net_backend_handler* handler, struct net_backend_common* common)
|
||||
{
|
||||
struct net_backend_select* backend;
|
||||
|
||||
net_close(con->sd);
|
||||
con->sd = -1;
|
||||
if (getenv("EVENT_NOSELECT"))
|
||||
return 0;
|
||||
|
||||
net_con_print("DEL", (struct net_connection_select*) con);
|
||||
net_cleanup_delayed_free(g_backend->cleaner, con);
|
||||
backend = hub_malloc_zero(sizeof(struct net_backend_select));
|
||||
FD_ZERO(&backend->rfds);
|
||||
FD_ZERO(&backend->wfds);
|
||||
backend->conns = hub_malloc_zero(sizeof(struct net_connection_select*) * common->max);
|
||||
backend->common = common;
|
||||
net_backend_set_handlers(handler);
|
||||
return (struct net_backend*) backend;
|
||||
}
|
||||
|
||||
static void net_backend_set_handlers(struct net_backend_handler* handler)
|
||||
{
|
||||
handler->backend_name = net_backend_name_select;
|
||||
handler->backend_poll = net_backend_poll_select;
|
||||
handler->backend_process = net_backend_process_select;
|
||||
handler->backend_shutdown = net_backend_shutdown_select;
|
||||
handler->con_create = net_con_create_select;
|
||||
handler->con_init = net_con_initialize_select;
|
||||
handler->con_add = net_con_backend_add_select;
|
||||
handler->con_mod = net_con_backend_mod_select;
|
||||
handler->con_del = net_con_backend_del_select;
|
||||
}
|
||||
|
||||
#endif /* USE_SELECT */
|
||||
|
||||
Reference in New Issue
Block a user