#include #include #include #include #include #include #include #include #include "main.h" #include "uring.h" #include "announce.h" #include "server.h" struct announce { uint64_t value; struct uring_task task; int mcast_fd; time_t until; }; static void announce_cb(struct uring_task *task, int res) { struct announce *announce = container_of(task, struct announce, task); struct server *server; assert_return(task); assert_task_alive(DBG_ANN, task); if (res != sizeof(announce->value)) { error("timerfd_read: %m"); return; } if (announce->until != 0 && time(NULL) > announce->until) { debug(DBG_ANN, "stopping announcements"); announce_stop(); } else { debug(DBG_ANN, "announcing servers"); list_for_each_entry(server, &cfg->servers, list) server_announce(server, announce->mcast_fd); } uring_read(&announce->task, &announce->value, sizeof(announce->value), announce_cb); } static void announce_free(struct uring_task *task) { struct announce *announce = container_of(task, struct announce, task); assert_return(task); debug(DBG_ANN, "task %p, announce 0x%p, mcast_fd: %i", task, announce, announce->mcast_fd); close(announce->mcast_fd); xfree(announce); } void announce_refdump() { assert_return_silent(cfg->announce); uring_task_refdump(&cfg->announce->task); } void announce_delete() { assert_return(cfg->announce); debug(DBG_ANN, "closing fd %i", cfg->announce->task.fd); uring_task_destroy(&cfg->announce->task); cfg->announce = NULL; } void announce_stop() { struct itimerspec tspec = { .it_interval = { .tv_sec = 0, .tv_nsec = 0 }, .it_value = { .tv_sec = 0, .tv_nsec = 0 } }; assert_return(cfg->announce); if (timerfd_settime(cfg->announce->task.fd, 0, &tspec, NULL) != 0) error("timerfd_settime: %m"); } void announce_start(unsigned duration) { struct itimerspec tspec = { .it_interval = { .tv_sec = 3, .tv_nsec = 0 }, .it_value = { .tv_sec = 3, .tv_nsec = 0 } }; assert_return(cfg->announce); if (duration > 0) cfg->announce->until = time(NULL) + duration; else cfg->announce->until = 0; if (timerfd_settime(cfg->announce->task.fd, 0, &tspec, NULL) != 0) error("timerfd_settime: %m"); } void announce_init() { struct announce *announce; int afd; int sfd; assert_return(!cfg->announce); announce = zmalloc(sizeof(*announce)); if (!announce) die("malloc: %m"); afd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); if (afd < 0) die("timerfd_create: %m"); sfd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); if (sfd < 0) die("socket: %m"); uring_task_init(&announce->task, "announce", uring_parent(), announce_free); uring_task_set_fd(&announce->task, afd); announce->mcast_fd = sfd; cfg->announce = announce; uring_read(&announce->task, &announce->value, sizeof(announce->value), announce_cb); }