#include #include #include #include #include #include #include "main.h" #include "uring.h" #include "config.h" #include "announce.h" #include "server.h" struct announce { uint64_t value; struct uring_task task; struct uring_task mcast_task; struct sockaddr_in mcast_addr; }; static void mcast_free(struct uring_task *task) { struct announce *aev = container_of(task, struct announce, mcast_task); fprintf(stderr, "%s: called with task 0x%p and aev 0x%p\n", __func__, task, aev); } static void mcast_sent(struct cfg *cfg, struct uring_task *task, int res) { fprintf(stderr, "%s: result %i\n", __func__, res); } static void mcast_send(struct cfg *cfg, struct announce *aev, struct server *server) { int len; if (!server || !server->pretty_name || server->announce_port < 1) return; len = snprintf(server->mcast_buf, sizeof(server->mcast_buf), "[MOTD]%s[/MOTD][AD]%" PRIu16 "[/AD]", server->pretty_name, server->announce_port); if (len < 1 || len >= sizeof(server->mcast_buf)) { error("%s: snprintf returned %i\n", __func__, len); return; } server->mcast_msg.msg_name = &aev->mcast_addr; server->mcast_msg.msg_namelen = sizeof(aev->mcast_addr); server->mcast_iov.iov_len = len; //uring_task_get(cfg, &server->task); <--- need to put in mcast_sent uring_sendmsg(cfg, &aev->mcast_task, &server->mcast_msg, mcast_sent); } static void mcast_send_all(struct cfg *cfg, struct announce *aev) { struct server *server; list_for_each_entry(server, &cfg->servers, list) { fprintf(stderr, "Announcing server: %s\n", server->name); mcast_send(cfg, aev, server); } } static void announce_cb(struct cfg *cfg, struct uring_task *task, int res) { struct announce *aev = container_of(task, struct announce, task); fprintf(stderr, "%s: ret is %i (ref %u)\n", __func__, res, task->refcount); if (task->dead) { fprintf(stderr, "%s: task is dead\n", __func__); uring_task_put(cfg, task); return; } if (res != sizeof(aev->value)) perrordie("timerfd_read"); fprintf(stderr, "%s: called with value %" PRIu64 "\n", __func__, aev->value); mcast_send_all(cfg, aev); uring_read(cfg, &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); fprintf(stderr, "%s: called with task 0x%p and aev 0x%p\n", __func__, task, aev); } void announce_refdump(struct announce *aev) { if (!aev) return; uring_task_refdump(&aev->task); uring_task_refdump(&aev->mcast_task); } void announce_delete(struct cfg *cfg) { if (!cfg->aev) { fprintf(stderr, "%s called with no announce!\n", __func__); return; } fprintf(stderr, "%s called, closing fd %i\n", __func__, cfg->aev->task.fd); uring_cancel(cfg, &cfg->aev->task); uring_task_put(cfg, &cfg->aev->mcast_task); cfg->aev = NULL; } void announce_stop(struct announce *aev) { struct itimerspec tspec = { .it_interval = { .tv_sec = 0, .tv_nsec = 0 }, .it_value = { .tv_sec = 0, .tv_nsec = 0 } }; if (timerfd_settime(aev->task.fd, 0, &tspec, NULL) != 0) perrordie("timerfd_settime"); } void announce_start(struct announce *aev) { struct itimerspec tspec = { .it_interval = { .tv_sec = 3, .tv_nsec = 0 }, .it_value = { .tv_sec = 3, .tv_nsec = 0 } }; if (timerfd_settime(aev->task.fd, 0, &tspec, NULL) != 0) perrordie("timerfd_settime"); } void announce_init(struct cfg *cfg) { struct announce *aev; int afd; int sfd; aev = zmalloc(sizeof(*aev)); if (!aev) perrordie("malloc"); afd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); if (afd < 0) perrordie("timerfd_create"); sfd = socket(AF_INET, SOCK_DGRAM, 0); if (sfd < 0) perrordie("socket"); uring_task_init(&aev->task, "aev", uring_parent(cfg), announce_free); uring_task_set_fd(&aev->task, afd); uring_task_init(&aev->mcast_task, "aev_mcast", &aev->task, mcast_free); uring_task_set_fd(&aev->mcast_task, sfd); memset(&aev->mcast_addr, 0, sizeof(aev->mcast_addr)); aev->mcast_addr.sin_family = AF_INET; aev->mcast_addr.sin_addr.s_addr = inet_addr("224.0.2.60"); aev->mcast_addr.sin_port = htons(4445); cfg->aev = aev; uring_read(cfg, &aev->task, &aev->value, sizeof(aev->value), announce_cb); }