summaryrefslogtreecommitdiff
path: root/announce.c
blob: f85ba1ecf56b1ff4ef5bcc9fcb1bd065357d3d7f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include <inttypes.h>
#include <sys/timerfd.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>

#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 cfg *cfg, struct uring_task *task, int res)
{
	struct announce *aev = container_of(task, struct announce, task);
	struct server *server;

	assert_return(cfg && 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(cfg, server, aev->mcast_fd);
	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);

	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(struct announce *aev)
{
	assert_return_silent(aev);

	uring_task_refdump(&aev->task);
}

void
announce_delete(struct cfg *cfg)
{
	assert_return(cfg && cfg->aev);

	debug(DBG_ANN, "closing fd %i", cfg->aev->task.fd);
	uring_task_destroy(cfg, &cfg->aev->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
		}
	};

	assert_return(aev);

	if (timerfd_settime(aev->task.fd, 0, &tspec, NULL) != 0)
		error("timerfd_settime: %m");
}

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
		}
	};

	assert_return(aev);

	if (timerfd_settime(aev->task.fd, 0, &tspec, NULL) != 0)
		error("timerfd_settime: %m");
}

void
announce_init(struct cfg *cfg)
{
	struct announce *aev;
	int afd;
	int sfd;
 
	assert_return(cfg);

	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(cfg, &aev->task, "aev", uring_parent(cfg), announce_free);
	uring_task_set_fd(&aev->task, afd);
	aev->mcast_fd = sfd;
	cfg->aev = aev;
	uring_read(cfg, &aev->task, &aev->value, sizeof(aev->value), announce_cb);
}