From 98bf08bdcf2edd9d397f32650a8bfe62186fbecf Mon Sep 17 00:00:00 2001 From: "Alfred E. Heggestad" Date: Sun, 9 Feb 2014 11:50:07 +0100 Subject: baresip 0.4.10 --- modules/turn/turn.c | 300 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 300 insertions(+) create mode 100644 modules/turn/turn.c (limited to 'modules/turn/turn.c') diff --git a/modules/turn/turn.c b/modules/turn/turn.c new file mode 100644 index 0000000..41588e6 --- /dev/null +++ b/modules/turn/turn.c @@ -0,0 +1,300 @@ +/** + * @file turn.c TURN Module + * + * Copyright (C) 2010 Creytiv.com + */ +#include +#include + + +/** + * @defgroup turn turn + * + * Traversal Using Relays around NAT (TURN) for media NAT traversal + * + * XXX: use turn RSV_TOKEN for RTP/RTCP even/odd pair ? + */ + + +enum {LAYER = 0}; + + +struct mnat_sess { + struct list medial; + struct sa srv; + struct stun_dns *dnsq; + char *user; + char *pass; + mnat_estab_h *estabh; + void *arg; + int mediac; +}; + + +struct mnat_media { + struct le le; + struct sa addr1; + struct sa addr2; + struct mnat_sess *sess; + struct sdp_media *sdpm; + struct turnc *turnc1; + struct turnc *turnc2; + void *sock1; + void *sock2; + int proto; +}; + + +static struct mnat *mnat; + + +static void session_destructor(void *arg) +{ + struct mnat_sess *sess = arg; + + list_flush(&sess->medial); + mem_deref(sess->dnsq); + mem_deref(sess->user); + mem_deref(sess->pass); +} + + +static void media_destructor(void *arg) +{ + struct mnat_media *m = arg; + + list_unlink(&m->le); + mem_deref(m->sdpm); + mem_deref(m->turnc1); + mem_deref(m->turnc2); + mem_deref(m->sock1); + mem_deref(m->sock2); +} + + +static void turn_handler1(int err, uint16_t scode, const char *reason, + const struct sa *relay_addr, + const struct sa *mapped_addr, + const struct stun_msg *msg, + void *arg) +{ + struct mnat_media *m = arg; + (void)mapped_addr; + (void)msg; + + if (!err && !scode) { + + sdp_media_set_laddr(m->sdpm, relay_addr); + + m->addr1 = *relay_addr; + + if (m->turnc2 && !sa_isset(&m->addr2, SA_ALL)) + return; + + if (--m->sess->mediac) + return; + } + + m->sess->estabh(err, scode, reason, m->sess->arg); +} + + +static void turn_handler2(int err, uint16_t scode, const char *reason, + const struct sa *relay_addr, + const struct sa *mapped_addr, + const struct stun_msg *msg, + void *arg) +{ + struct mnat_media *m = arg; + (void)mapped_addr; + (void)msg; + + if (!err && !scode) { + + sdp_media_set_laddr_rtcp(m->sdpm, relay_addr); + + m->addr2 = *relay_addr; + + if (m->turnc1 && !sa_isset(&m->addr1, SA_ALL)) + return; + + if (--m->sess->mediac) + return; + } + + m->sess->estabh(err, scode, reason, m->sess->arg); +} + + +static int media_start(struct mnat_sess *sess, struct mnat_media *m) +{ + int err = 0; + + if (m->sock1) { + err |= turnc_alloc(&m->turnc1, NULL, + m->proto, m->sock1, LAYER, + &sess->srv, sess->user, sess->pass, + TURN_DEFAULT_LIFETIME, + turn_handler1, m); + } + if (m->sock2) { + err |= turnc_alloc(&m->turnc2, NULL, + m->proto, m->sock2, LAYER, + &sess->srv, sess->user, sess->pass, + TURN_DEFAULT_LIFETIME, + turn_handler2, m); + } + + return err; +} + + +static void dns_handler(int err, const struct sa *srv, void *arg) +{ + struct mnat_sess *sess = arg; + struct le *le; + + if (err) + goto out; + + sess->srv = *srv; + + for (le=sess->medial.head; le; le=le->next) { + + struct mnat_media *m = le->data; + + err = media_start(sess, m); + if (err) + goto out; + } + + return; + + out: + sess->estabh(err, 0, NULL, sess->arg); +} + + +static int session_alloc(struct mnat_sess **sessp, struct dnsc *dnsc, + int af, const char *srv, uint16_t port, + const char *user, const char *pass, + struct sdp_session *ss, bool offerer, + mnat_estab_h *estabh, void *arg) +{ + struct mnat_sess *sess; + int err; + (void)ss; + (void)offerer; + + if (!sessp || !dnsc || !srv || !user || !pass || !ss || !estabh) + return EINVAL; + + sess = mem_zalloc(sizeof(*sess), session_destructor); + if (!sess) + return ENOMEM; + + err = str_dup(&sess->user, user); + err |= str_dup(&sess->pass, pass); + if (err) + goto out; + + sess->estabh = estabh; + sess->arg = arg; + + err = stun_server_discover(&sess->dnsq, dnsc, + stun_usage_relay, stun_proto_udp, + af, srv, port, dns_handler, sess); + + out: + if (err) + mem_deref(sess); + else + *sessp = sess; + + return err; +} + + +static int media_alloc(struct mnat_media **mp, struct mnat_sess *sess, + int proto, void *sock1, void *sock2, + struct sdp_media *sdpm) +{ + struct mnat_media *m; + int err = 0; + + if (!mp || !sess || !sdpm) + return EINVAL; + + m = mem_zalloc(sizeof(*m), media_destructor); + if (!m) + return ENOMEM; + + list_append(&sess->medial, &m->le, m); + m->sdpm = mem_ref(sdpm); + m->sess = sess; + m->sock1 = mem_ref(sock1); + m->sock2 = mem_ref(sock2); + m->proto = proto; + + if (sa_isset(&sess->srv, SA_ALL)) + err = media_start(sess, m); + + if (err) + mem_deref(m); + else { + *mp = m; + ++sess->mediac; + } + + return err; +} + + +static int update(struct mnat_sess *sess) +{ + struct le *le; + int err = 0; + + if (!sess) + return EINVAL; + + for (le=sess->medial.head; le; le=le->next) { + + struct mnat_media *m = le->data; + struct sa raddr1, raddr2; + + raddr1 = *sdp_media_raddr(m->sdpm); + sdp_media_raddr_rtcp(m->sdpm, &raddr2); + + if (m->turnc1 && sa_isset(&raddr1, SA_ALL)) + err |= turnc_add_chan(m->turnc1, &raddr1, NULL, NULL); + + if (m->turnc2 && sa_isset(&raddr2, SA_ALL)) + err |= turnc_add_chan(m->turnc2, &raddr2, NULL, NULL); + } + + return err; +} + + +static int module_init(void) +{ + return mnat_register(&mnat, "turn", NULL, session_alloc, media_alloc, + update); +} + + +static int module_close(void) +{ + mnat = mem_deref(mnat); + + return 0; +} + + +EXPORT_SYM const struct mod_export DECL_EXPORTS(turn) = { + "turn", + "mnat", + module_init, + module_close, +}; -- cgit v1.2.3