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
|
/**
* @file listener.c Port Control Protocol module -- multicast listener
*
* Copyright (C) 2010 - 2016 Creytiv.com
*/
#include <re.h>
#include <rew.h>
#include <baresip.h>
#include "pcp.h"
/*
* Listen for incoming notifications on unicast/multicast port 5350
*/
struct pcp_listener {
struct udp_sock *us;
struct sa srv;
struct sa group;
pcp_msg_h *msgh;
void *arg;
};
static void destructor(void *arg)
{
struct pcp_listener *pl = arg;
if (sa_isset(&pl->group, SA_ADDR))
(void)udp_multicast_leave(pl->us, &pl->group);
mem_deref(pl->us);
}
static void udp_recv(const struct sa *src, struct mbuf *mb, void *arg)
{
struct pcp_listener *pl = arg;
struct pcp_msg *msg;
int err;
#if 0
if (!sa_cmp(src, &pl->srv, SA_ADDR)) {
debug("pcp: listener: ignore %zu bytes from non-server %J\n",
mb->end, src);
return;
}
#endif
err = pcp_msg_decode(&msg, mb);
if (err)
return;
/* Validate PCP request */
if (!msg->hdr.resp) {
info("pcp: listener: ignore request from %J\n", src);
goto out;
}
if (pl->msgh)
pl->msgh(msg, pl->arg);
out:
mem_deref(msg);
}
int pcp_listen(struct pcp_listener **plp, const struct sa *srv,
pcp_msg_h *msgh, void *arg)
{
struct pcp_listener *pl;
struct sa laddr;
int err;
if (!plp || !srv || !msgh)
return EINVAL;
pl = mem_zalloc(sizeof(*pl), destructor);
if (!pl)
return ENOMEM;
pl->srv = *srv;
pl->msgh = msgh;
pl->arg = arg;
/* note: must listen on ANY to get multicast working */
sa_init(&laddr, sa_af(srv));
sa_set_port(&laddr, PCP_PORT_CLI);
err = udp_listen(&pl->us, &laddr, udp_recv, pl);
if (err)
goto out;
switch (sa_af(&laddr)) {
case AF_INET:
err = sa_set_str(&pl->group, "224.0.0.1", 0);
break;
case AF_INET6:
err = sa_set_str(&pl->group, "ff02::1", 0);
break;
default:
err = EAFNOSUPPORT;
break;
}
if (err)
goto out;
err = udp_multicast_join(pl->us, &pl->group);
if (err)
goto out;
out:
if (err)
mem_deref(pl);
else
*plp = pl;
return err;
}
|