#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; }; static void announce_cb(struct uring_task *task, int res) { struct announce *aev = container_of(task, struct announce, task); struct server *server; assert_return(task); assert_task_alive(DBG_ANN, task); if (res != sizeof(aev->value)) { error("timerfd_read: %m"); return; } debug(DBG_ANN, "timerfd value %" PRIu64, aev->value); list_for_each_entry(server, &cfg->servers, list) server_announce(server, aev->mcast_fd); uring_read(&aev->task, &aev->value, sizeof(aev->value), announce_cb); } static void announce_free(struct uring_task *task) { struct announce *aev = container_of(task, struct announce, task); assert_return(task); debug(DBG_ANN, "task %p, aev 0x%p, mcast_fd: %i", task, aev, aev->mcast_fd); close(aev->mcast_fd); xfree(aev); } void announce_refdump() { assert_return_silent(cfg->aev); uring_task_refdump(&cfg->aev->task); } void announce_delete() { assert_return(cfg->aev); debug(DBG_ANN, "closing fd %i", cfg->aev->task.fd); uring_task_destroy(&cfg->aev->task); cfg->aev = 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->aev); if (timerfd_settime(cfg->aev->task.fd, 0, &tspec, NULL) != 0) error("timerfd_settime: %m"); } void announce_start() { struct itimerspec tspec = { .it_interval = { .tv_sec = 3, .tv_nsec = 0 }, .it_value = { .tv_sec = 3, .tv_nsec = 0 } }; assert_return(cfg->aev); if (timerfd_settime(cfg->aev->task.fd, 0, &tspec, NULL) != 0) error("timerfd_settime: %m"); } void announce_init() { struct announce *aev; int afd; int sfd; assert_return(!cfg->aev); aev = zmalloc(sizeof(*aev)); if (!aev) 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(&aev->task, "announce", uring_parent(), announce_free); uring_task_set_fd(&aev->task, afd); aev->mcast_fd = sfd; cfg->aev = aev; uring_read(&aev->task, &aev->value, sizeof(aev->value), announce_cb); }