From 94bbdce6b742ab2f62cfa9513e13f27a0f78973b Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Mon, 22 Jun 2020 01:41:52 +0200 Subject: Split idle into top-level task and per-server tasks --- idle.c | 112 +++++++++++++++------------------------------------------------ idle.h | 7 ++-- main.c | 5 +++ main.h | 1 + server.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++--- server.h | 9 ++++- 6 files changed, 135 insertions(+), 93 deletions(-) diff --git a/idle.c b/idle.c index bfb8fc8..0ced98d 100644 --- a/idle.c +++ b/idle.c @@ -15,25 +15,10 @@ #include "idle.h" struct idle { - struct server *server; - struct uring_task task; uint64_t value; - - struct uring_task idlecheck; - struct connection conn; - struct uring_task_buf tbuf; }; -static void -idle_check_free(struct uring_task *task) -{ - struct idle *idle = container_of(task, struct idle, idlecheck); - - assert_return(task && idle); - debug(DBG_IDLE, "task %p, idle %p", task, idle); -} - static inline void write_byte(char **pos, char byte) { @@ -209,12 +194,12 @@ get_player_count(struct cfg *cfg, const char *pos, size_t remain) static void idle_check_handshake_reply(struct cfg *cfg, struct uring_task *task, int res) { - struct idle *idle = container_of(task, struct idle, idlecheck); + struct server *server = container_of(task, struct server, idle_task); int32_t mclen; int32_t jsonlen; char *pos; size_t remain; - int player_count; + int player_count = -1; int r; assert_return(cfg && task); @@ -231,8 +216,8 @@ idle_check_handshake_reply(struct cfg *cfg, struct uring_task *task, int res) fprintf(stderr, "n"); */ - remain = idle->tbuf.len; - pos = idle->tbuf.buf; + remain = server->idle_buf.len; + pos = server->idle_buf.buf; r = read_varint(&pos, &remain, &mclen); if (r <= 0 || mclen < 2 || mclen < remain) { @@ -273,34 +258,16 @@ idle_check_handshake_reply(struct cfg *cfg, struct uring_task *task, int res) */ player_count = get_player_count(cfg, pos, remain); - if (player_count < 0) - goto out; - - idle->server->state = SERVER_STATE_RUNNING; - - debug(DBG_IDLE, "%s: currently %i active players", - idle->server->name, player_count); - - if (player_count > 0) - idle->server->idle_count = 0; - else if (player_count == 0) - idle->server->idle_count++; - - if (idle->server->idle_count > idle->server->idle_timeout) { - verbose("stopping idle server %s", idle->server->name); - server_stop(cfg, idle->server); - } out: uring_task_close_fd(cfg, task); + server_set_active_players(cfg, server, player_count); return; } static void idle_check_handshake_sent(struct cfg *cfg, struct uring_task *task, int res) { - struct idle *idle = container_of(task, struct idle, idlecheck); - assert_return(cfg && task); assert_task_alive(DBG_IDLE, task); @@ -310,34 +277,22 @@ idle_check_handshake_sent(struct cfg *cfg, struct uring_task *task, int res) return; } - uring_tbuf_read_until(cfg, &idle->idlecheck, + uring_tbuf_read_until(cfg, task, idle_check_handshake_complete, idle_check_handshake_reply); } -static void -idle_check_connected_cb(struct cfg *cfg, struct connection *conn, bool connected) +void +idle_check_get_player_count(struct cfg *cfg, struct server *server, + struct connection *conn) { - struct idle *idle = container_of(conn, struct idle, conn); char buf[1024]; char *pos; - char *cmdbuf = idle->tbuf.buf; + char *cmdbuf = server->idle_buf.buf; uint16_t port; char hostname[INET6_ADDRSTRLEN]; - assert_return(cfg && conn); - assert_task_alive(DBG_IDLE, &idle->idlecheck); - - if (!connected) { - debug(DBG_IDLE, - "idle check connection to remote server (%s) failed", - idle->server->name); - idle->server->idle_count = 0; - idle->server->state = SERVER_STATE_STOPPED; - return; - } - - debug(DBG_IDLE, "connected to remote %s", idle->conn.remote.addrstr); + assert_return(cfg && server && conn && server->idle_task.priv); port = saddr_port(&conn->remote); saddr_addr(&conn->remote, hostname, sizeof(hostname)); @@ -355,16 +310,17 @@ idle_check_connected_cb(struct cfg *cfg, struct connection *conn, bool connected write_byte(&pos, MC_GET_STATUS); write_cmd(&cmdbuf, buf, pos); - idle->tbuf.len = (cmdbuf - idle->tbuf.buf); - debug(DBG_IDLE, "sending MC message (%zu bytes)", idle->tbuf.len); + server->idle_buf.len = (cmdbuf - server->idle_buf.buf); + debug(DBG_IDLE, "sending MC message (%zu bytes)", server->idle_buf.len); - uring_tbuf_write(cfg, &idle->idlecheck, idle_check_handshake_sent); + uring_tbuf_write(cfg, &server->idle_task, idle_check_handshake_sent); } static void idle_cb(struct cfg *cfg, struct uring_task *task, int res) { struct idle *idle = container_of(task, struct idle, task); + struct server *server; assert_return(cfg && task); assert_task_alive(DBG_IDLE, task); @@ -376,11 +332,8 @@ idle_cb(struct cfg *cfg, struct uring_task *task, int res) debug(DBG_IDLE, "timer fired (value: %" PRIu64 ")", idle->value); - if (!list_empty(&idle->server->proxys)) - idle->server->idle_count = 0; - else - connect_any(cfg, &idle->idlecheck, &idle->server->remotes, - &idle->conn, idle_check_connected_cb); + list_for_each_entry(server, &cfg->servers, list) + server_idle_check(cfg, server); uring_read(cfg, &idle->task, &idle->value, sizeof(idle->value), idle_cb); } @@ -401,26 +354,21 @@ idle_refdump(struct idle *idle) assert_return_silent(idle); uring_task_refdump(&idle->task); - uring_task_refdump(&idle->idlecheck); } void -idle_delete(struct cfg *cfg, struct server *server) +idle_delete(struct cfg *cfg) { - struct idle *idle; + assert_return(cfg); + assert_return_silent(cfg->idle); - assert_return(cfg && server); - assert_return_silent(server->idle); - - idle = server->idle; - debug(DBG_IDLE, "closing fd %i", idle->task.fd); - uring_task_destroy(cfg, &idle->idlecheck); - uring_task_destroy(cfg, &idle->task); - server->idle = NULL; + debug(DBG_IDLE, "closing fd %i", cfg->idle->task.fd); + uring_task_destroy(cfg, &cfg->idle->task); + cfg->idle = NULL; } void -idle_init(struct cfg *cfg, struct server *server) +idle_init(struct cfg *cfg) { struct idle *idle; int ifd; @@ -436,10 +384,7 @@ idle_init(struct cfg *cfg, struct server *server) } }; - assert_return(cfg && server); - - if (server->idle_timeout < 1) - return; + assert_return(cfg); idle = zmalloc(sizeof(*idle)); if (!idle) @@ -452,12 +397,9 @@ idle_init(struct cfg *cfg, struct server *server) if (timerfd_settime(ifd, 0, &tspec, NULL) != 0) die("timerfd_settime: %m"); - uring_task_init(cfg, &idle->task, "idle", &server->task, idle_free); + uring_task_init(cfg, &idle->task, "idle", uring_parent(cfg), idle_free); uring_task_set_fd(&idle->task, ifd); - uring_task_init(cfg, &idle->idlecheck, "idlecheck", &idle->task, idle_check_free); - uring_task_set_buf(&idle->idlecheck, &idle->tbuf); - idle->server = server; - server->idle = idle; + cfg->idle = idle; uring_read(cfg, &idle->task, &idle->value, sizeof(idle->value), idle_cb); } diff --git a/idle.h b/idle.h index d15ee9b..a0bf5c2 100644 --- a/idle.h +++ b/idle.h @@ -1,10 +1,13 @@ #ifndef fooidlehfoo #define fooidlehfoo +void idle_check_get_player_count(struct cfg *cfg, struct server *server, + struct connection *conn); + void idle_refdump(struct idle *idle); -void idle_delete(struct cfg *cfg, struct server *server); +void idle_delete(struct cfg *cfg); -void idle_init(struct cfg *cfg, struct server *server); +void idle_init(struct cfg *cfg); #endif diff --git a/main.c b/main.c index 1887a5d..df1f958 100644 --- a/main.c +++ b/main.c @@ -26,6 +26,7 @@ #include "announce.h" #include "systemd.h" #include "igmp.h" +#include "idle.h" #define DEFAULT_HOMEDIR_PATH "/home/david/intest" #define DEFAULT_MAIN_CONFIG_FILE_PATH "./mcproxy.conf" @@ -577,6 +578,7 @@ dump_tree(struct cfg *cfg) debug(DBG_REF, "============"); uring_task_refdump(&cfg->task); uring_refdump(cfg->uev); + idle_refdump(cfg->idle); if (cfg->sev) uring_task_refdump(&cfg->sev->task); igmp_refdump(cfg->igmp); @@ -614,6 +616,7 @@ signalfd_read(struct cfg *cfg, struct uring_task *task, int res) uring_task_put(cfg, &sev->task); igmp_delete(cfg); announce_delete(cfg); + idle_delete(cfg); cfgdir_delete(cfg); list_for_each_entry_safe(server, stmp, &cfg->servers, list) server_delete(cfg, server); @@ -774,6 +777,8 @@ main(int argc, char **argv) announce_start(cfg->aev); + idle_init(cfg); + uring_task_put(cfg, &cfg->task); server_count = 0; diff --git a/main.h b/main.h index 5dff164..e418f38 100644 --- a/main.h +++ b/main.h @@ -150,6 +150,7 @@ struct cfg { struct signalfd_ev *sev; struct announce *aev; struct igmp *igmp; + struct idle *idle; struct sd_bus *sd_bus; bool sd_bus_failed; struct uring_task task; diff --git a/server.c b/server.c index 4a45b53..145bcf9 100644 --- a/server.c +++ b/server.c @@ -56,11 +56,11 @@ server_refdump(struct server *server) uring_task_refdump(&server->task); uring_task_refdump(&server->exec_task); uring_task_refdump(&server->ann_task); + uring_task_refdump(&server->idle_task); list_for_each_entry(local, &server->locals, list) uring_task_refdump(&local->task); list_for_each_entry(proxy, &server->proxys, list) proxy_refdump(proxy); - idle_refdump(server->idle); rcon_refdump(server->rcon); } @@ -98,7 +98,6 @@ server_delete(struct cfg *cfg, struct server *server) verbose("Removing server %s", server->name); server->state = SERVER_STATE_DEAD; - idle_delete(cfg, server); rcon_delete(cfg, server); list_for_each_entry_safe(local, ltmp, &server->locals, list) @@ -120,6 +119,7 @@ server_delete(struct cfg *cfg, struct server *server) list_for_each_entry_safe(dns, dtmp, &server->dnslookups, list) gai_cancel(&dns->gcb); + uring_task_destroy(cfg, &server->idle_task); uring_poll_cancel(cfg, &server->exec_task); uring_task_put(cfg, &server->exec_task); uring_task_destroy(cfg, &server->task); @@ -363,7 +363,7 @@ server_exec(struct cfg *cfg, struct server *server, const char *cmd) CLONE_VM | CLONE_VFORK | CLONE_PIDFD | SIGCHLD, (void *)cmd, &pidfd); if (r != 0) { - error("clone: %m"); + error("clone: %m: %i", r); return false; } @@ -456,6 +456,84 @@ server_stop(struct cfg *cfg, struct server *server) return false; } +static void +server_idle_free(struct uring_task *task) +{ + assert_return(task); + + debug(DBG_ANN, "called"); +} + +void +server_set_active_players(struct cfg *cfg, struct server *server, int count) +{ + assert_return(cfg && server); + assert_task_alive(DBG_IDLE, &server->idle_task); + + debug(DBG_IDLE, "%s: currently %i active players", + server->name, count); + + if (count < 0) + return; + + server->state = SERVER_STATE_RUNNING; + if (count > 0) + server->idle_count = 0; + else if (count == 0) + server->idle_count++; + + if (server->idle_count > server->idle_timeout) { + verbose("stopping idle server %s", server->name); + server_stop(cfg, server); + } +} + +static void +server_idle_connected_cb(struct cfg *cfg, struct connection *conn, bool connected) +{ + struct server *server = container_of(conn, struct server, idle_conn); + + assert_return(cfg && conn); + assert_task_alive(DBG_IDLE, &server->idle_task); + + if (!connected) { + debug(DBG_IDLE, + "idle check connection to remote server (%s) failed", + server->name); + server->idle_count = 0; + server->state = SERVER_STATE_STOPPED; + return; + } + + debug(DBG_IDLE, "connected to remote %s\n", conn->remote.addrstr); + idle_check_get_player_count(cfg, server, conn); +} + +bool +server_idle_check(struct cfg *cfg, struct server *server) +{ + assert_return(cfg && server, false); + + if (server->state == SERVER_STATE_INIT || + server->state == SERVER_STATE_DEAD) + return false; + + if (server->idle_timeout < 1) + return false; + + if (list_empty(&server->remotes)) + return false; + + if (!list_empty(&server->proxys)) { + server->idle_count = 0; + return true; + } + + connect_any(cfg, &server->idle_task, &server->remotes, + &server->idle_conn, server_idle_connected_cb); + return true; +} + static void server_announce_free(struct uring_task *task) { @@ -658,7 +736,6 @@ server_commit(struct cfg *cfg, struct server *server) server_local_open(cfg, server, local); } - idle_init(cfg, server); server->state = SERVER_STATE_CFG_OK; server_check_running(cfg, server); @@ -856,18 +933,25 @@ server_new(struct cfg *cfg, const char *name) server->name = xstrdup(name); server->stop_method = SERVER_STOP_METHOD_UNDEFINED; server->start_method = SERVER_START_METHOD_UNDEFINED; + server->idle_timeout = 0; + uring_task_init(cfg, &server->task, "server", uring_parent(cfg), server_free); uring_task_set_buf(&server->task, &server->tbuf); + uring_task_init(cfg, &server->ann_task, "announce", &server->task, server_announce_free); uring_task_set_buf(&server->ann_task, &server->ann_buf); saddr_set_ipv4(&server->ann_task.saddr, cinet_addr(224,0,2,60), htons(4445)); + uring_task_init(cfg, &server->exec_task, "exec", &server->task, server_exec_free); + + uring_task_init(cfg, &server->idle_task, "idle", &server->task, server_idle_free); + uring_task_set_buf(&server->idle_task, &server->idle_buf); + list_init(&server->remotes); list_init(&server->locals); list_init(&server->proxys); list_init(&server->rcons); list_init(&server->dnslookups); - server->idle_timeout = 0; list_add(&server->list, &cfg->servers); return server; diff --git a/server.h b/server.h index 46fac3f..b104ef1 100644 --- a/server.h +++ b/server.h @@ -62,7 +62,9 @@ struct server { struct uring_task_buf ann_buf; /* For checking idle status */ - struct idle *idle; + struct uring_task idle_task; + struct connection idle_conn; + struct uring_task_buf idle_buf; unsigned idle_timeout; unsigned idle_count; @@ -83,6 +85,11 @@ bool server_start(struct cfg *cfg, struct server *server); bool server_stop(struct cfg *cfg, struct server *server); +void server_set_active_players(struct cfg *cfg, struct server *server, + int count); + +bool server_idle_check(struct cfg *cfg, struct server *server); + bool server_announce(struct cfg *cfg, struct server *server, int fd); bool server_commit(struct cfg *cfg, struct server *server); -- cgit v1.2.3