diff options
Diffstat (limited to 'modules/pcp/listener.c')
-rw-r--r-- | modules/pcp/listener.c | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/modules/pcp/listener.c b/modules/pcp/listener.c new file mode 100644 index 0000000..7747672 --- /dev/null +++ b/modules/pcp/listener.c @@ -0,0 +1,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; +} |