summaryrefslogtreecommitdiff
path: root/minecproxy/announce.c
blob: 3e4a31edda06dea9906e39c299091b6394501e7a (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
/* SPDX-License-Identifier: GPL-2.0 */
#include <inttypes.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>

#include "minecproxy.h"
#include "uring.h"
#include "announce.h"
#include "server.h"
#include "ptimer.h"

struct announce {
	uint64_t value;
	struct uring_task task;
	struct ptimer_task ptask;
	int mcast_fd;
};

static void announce_cb(struct ptimer_task *ptask)
{
	struct announce *announce = container_of(ptask, struct announce, ptask);
	struct server *server;

	assert_return(ptask);
	assert_task_alive(DBG_ANN, &announce->task);

	debug(DBG_ANN, "announcing servers");
	list_for_each_entry(server, &cfg->servers, list)
		server_announce(server, announce->mcast_fd);
}

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_silent(cfg->announce);

	debug(DBG_ANN, "called");
	announce_stop();
	uring_task_destroy(&cfg->announce->task);
	cfg->announce = NULL;
}

void announce_stop()
{
	struct announce *announce = cfg->announce;

	assert_return_silent(announce);

	ptimer_del_task(&announce->ptask);
}

void announce_start(unsigned duration)
{
	struct announce *announce = cfg->announce;
	unsigned times;

	assert_return_silent(announce);

	if (duration == 0)
		times = 0;
	else
		times = MAX(announce->ptask.times,
			    DIV_ROUND_UP(duration, cfg->announce_interval));

	announce->ptask.times = times;
	ptimer_add_task(&announce->ptask);
}

void announce_init()
{
	struct announce *announce;
	int sfd;

	assert_return(!cfg->announce);
	assert_return_silent(cfg->announce_interval > 0);

	announce = zmalloc(sizeof(*announce));
	if (!announce)
		die("malloc: %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);
	ptask_init(&announce->ptask, cfg->announce_interval, 0, announce_cb);
	announce->mcast_fd = sfd;
	cfg->announce = announce;
}