summaryrefslogtreecommitdiff
path: root/announce.c
blob: 22dd080affe87632fb2638d62b6996273bbd3582 (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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#include <inttypes.h>
#include <sys/timerfd.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <string.h>

#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), 0, 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);
	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), 0, announce_cb);
}