summaryrefslogtreecommitdiff
path: root/src/net.c
diff options
context:
space:
mode:
authorAlfred E. Heggestad <aeh@db.org>2014-02-09 11:50:07 +0100
committerAlfred E. Heggestad <aeh@db.org>2014-02-09 11:50:07 +0100
commit98bf08bdcf2edd9d397f32650a8bfe62186fbecf (patch)
treeebc6ec71f44bff8c42e4eefced61948623df02fc /src/net.c
parente6ad5cf4401b860ba402d4b7b3c7c254bc87a019 (diff)
baresip 0.4.10
Diffstat (limited to 'src/net.c')
-rw-r--r--src/net.c439
1 files changed, 439 insertions, 0 deletions
diff --git a/src/net.c b/src/net.c
new file mode 100644
index 0000000..4829a5a
--- /dev/null
+++ b/src/net.c
@@ -0,0 +1,439 @@
+/**
+ * @file net.c Networking code
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#include <re.h>
+#include <baresip.h>
+#include "core.h"
+
+
+static struct {
+ struct config_net cfg;
+ struct sa laddr;
+ char ifname[16];
+#ifdef HAVE_INET6
+ struct sa laddr6;
+ char ifname6[16];
+#endif
+ struct tmr tmr;
+ struct dnsc *dnsc;
+ struct sa nsv[4]; /**< Configured name servers */
+ uint32_t nsn; /**< Number of configured name servers */
+ uint32_t interval;
+ int af; /**< Preferred address family */
+ char domain[64]; /**< DNS domain from network */
+ net_change_h *ch;
+ void *arg;
+} net;
+
+
+/**
+ * Check for DNS Server updates
+ */
+static void dns_refresh(void)
+{
+ struct sa nsv[8];
+ uint32_t i, nsn;
+ int err;
+
+ nsn = ARRAY_SIZE(nsv);
+
+ err = dns_srv_get(NULL, 0, nsv, &nsn);
+ if (err)
+ return;
+
+ for (i=0; i<net.nsn; i++)
+ sa_cpy(&nsv[nsn++], &net.nsv[i]);
+
+ (void)dnsc_srv_set(net.dnsc, nsv, nsn);
+}
+
+
+/**
+ * Detect changes in IP address(es)
+ */
+static void ipchange_handler(void *arg)
+{
+ bool change;
+ (void)arg;
+
+ tmr_start(&net.tmr, net.interval * 1000, ipchange_handler, NULL);
+
+ dns_refresh();
+
+ change = net_check();
+ if (change && net.ch) {
+ net.ch(net.arg);
+ }
+}
+
+
+/**
+ * Check if local IP address(es) changed
+ *
+ * @return True if changed, otherwise false
+ */
+bool net_check(void)
+{
+ struct sa laddr = net.laddr;
+#ifdef HAVE_INET6
+ struct sa laddr6 = net.laddr6;
+#endif
+ bool change = false;
+
+ if (str_isset(net.cfg.ifname)) {
+
+ (void)net_if_getaddr(net.cfg.ifname, AF_INET, &net.laddr);
+
+#ifdef HAVE_INET6
+ (void)net_if_getaddr(net.cfg.ifname, AF_INET6, &net.laddr6);
+#endif
+ }
+ else {
+ (void)net_default_source_addr_get(AF_INET, &net.laddr);
+ (void)net_rt_default_get(AF_INET, net.ifname,
+ sizeof(net.ifname));
+
+#ifdef HAVE_INET6
+ (void)net_default_source_addr_get(AF_INET6, &net.laddr6);
+ (void)net_rt_default_get(AF_INET6, net.ifname6,
+ sizeof(net.ifname6));
+#endif
+ }
+
+ if (sa_isset(&net.laddr, SA_ADDR) &&
+ !sa_cmp(&laddr, &net.laddr, SA_ADDR)) {
+ change = true;
+ info("net: local IPv4 address changed: %j -> %j\n",
+ &laddr, &net.laddr);
+ }
+
+#ifdef HAVE_INET6
+ if (sa_isset(&net.laddr6, SA_ADDR) &&
+ !sa_cmp(&laddr6, &net.laddr6, SA_ADDR)) {
+ change = true;
+ info("net: local IPv6 address changed: %j -> %j\n",
+ &laddr6, &net.laddr6);
+ }
+#endif
+
+ return change;
+}
+
+
+static int dns_init(void)
+{
+ struct sa nsv[8];
+ uint32_t i, nsn;
+ int err;
+
+ nsn = ARRAY_SIZE(nsv);
+
+ err = dns_srv_get(net.domain, sizeof(net.domain), nsv, &nsn);
+ if (err) {
+ nsn = 0;
+ }
+
+ /* Add any configured nameservers */
+ for (i=0; i<net.nsn && nsn < ARRAY_SIZE(nsv); i++)
+ sa_cpy(&nsv[nsn++], &net.nsv[i]);
+
+ return dnsc_alloc(&net.dnsc, NULL, nsv, nsn);
+}
+
+
+/**
+ * Return TRUE if libre supports IPv6
+ */
+static bool check_ipv6(void)
+{
+ struct sa sa;
+
+ return 0 == sa_set_str(&sa, "::1", 2000);
+}
+
+
+/**
+ * Initialise networking
+ *
+ * @param cfg Network configuration
+ * @param af Preferred address family
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int net_init(const struct config_net *cfg, int af)
+{
+ int err;
+
+ if (!cfg)
+ return EINVAL;
+
+ /*
+ * baresip/libre must be built with matching HAVE_INET6 value.
+ * if different the size of `struct sa' will not match and the
+ * application is very likely to crash.
+ */
+#ifdef HAVE_INET6
+ if (!check_ipv6()) {
+ error("libre was compiled without IPv6-support"
+ ", but baresip was compiled with\n");
+ return EAFNOSUPPORT;
+ }
+#else
+ if (check_ipv6()) {
+ error("libre was compiled with IPv6-support"
+ ", but baresip was compiled without\n");
+ return EAFNOSUPPORT;
+ }
+#endif
+
+ net.cfg = *cfg;
+ net.af = af;
+
+ tmr_init(&net.tmr);
+
+ /* Initialise DNS resolver */
+ err = dns_init();
+ if (err) {
+ warning("net: dns_init: %m\n", err);
+ return err;
+ }
+
+ sa_init(&net.laddr, AF_INET);
+ (void)sa_set_str(&net.laddr, "127.0.0.1", 0);
+
+ if (str_isset(cfg->ifname)) {
+
+ bool got_it = false;
+
+ info("Binding to interface '%s'\n", cfg->ifname);
+
+ str_ncpy(net.ifname, cfg->ifname, sizeof(net.ifname));
+
+ err = net_if_getaddr(cfg->ifname,
+ AF_INET, &net.laddr);
+ if (err) {
+ info("net: %s: could not get IPv4 address (%m)\n",
+ cfg->ifname, err);
+ }
+ else
+ got_it = true;
+
+#ifdef HAVE_INET6
+ str_ncpy(net.ifname6, cfg->ifname,
+ sizeof(net.ifname6));
+
+ err = net_if_getaddr(cfg->ifname,
+ AF_INET6, &net.laddr6);
+ if (err) {
+ info("net: %s: could not get IPv6 address (%m)\n",
+ cfg->ifname, err);
+ }
+ else
+ got_it = true;
+#endif
+ if (got_it)
+ err = 0;
+ else {
+ warning("net: %s: could not get network address\n",
+ cfg->ifname);
+ return EADDRNOTAVAIL;
+ }
+ }
+ else {
+ (void)net_default_source_addr_get(AF_INET, &net.laddr);
+ (void)net_rt_default_get(AF_INET, net.ifname,
+ sizeof(net.ifname));
+
+#ifdef HAVE_INET6
+ sa_init(&net.laddr6, AF_INET6);
+
+ (void)net_default_source_addr_get(AF_INET6, &net.laddr6);
+ (void)net_rt_default_get(AF_INET6, net.ifname6,
+ sizeof(net.ifname6));
+#endif
+ }
+
+ (void)re_fprintf(stderr, "Local network address:");
+
+ if (sa_isset(&net.laddr, SA_ADDR)) {
+ (void)re_fprintf(stderr, " IPv4=%s:%j",
+ net.ifname, &net.laddr);
+ }
+#ifdef HAVE_INET6
+ if (sa_isset(&net.laddr6, SA_ADDR)) {
+ (void)re_fprintf(stderr, " IPv6=%s:%j",
+ net.ifname6, &net.laddr6);
+ }
+#endif
+ (void)re_fprintf(stderr, "\n");
+
+ return err;
+}
+
+
+/**
+ * Reset the DNS resolver
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int net_reset(void)
+{
+ net.dnsc = mem_deref(net.dnsc);
+
+ return dns_init();
+}
+
+
+/**
+ * Close networking
+ */
+void net_close(void)
+{
+ net.dnsc = mem_deref(net.dnsc);
+ tmr_cancel(&net.tmr);
+}
+
+
+/**
+ * Add a DNS server
+ *
+ * @param sa DNS Server IP address and port
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int net_dnssrv_add(const struct sa *sa)
+{
+ if (net.nsn >= ARRAY_SIZE(net.nsv))
+ return E2BIG;
+
+ sa_cpy(&net.nsv[net.nsn++], sa);
+
+ return 0;
+}
+
+
+/**
+ * Check for networking changes with a regular interval
+ *
+ * @param interval Interval in seconds
+ * @param ch Handler called when a change was detected
+ * @param arg Handler argument
+ */
+void net_change(uint32_t interval, net_change_h *ch, void *arg)
+{
+ net.interval = interval;
+ net.ch = ch;
+ net.arg = arg;
+
+ if (interval)
+ tmr_start(&net.tmr, interval * 1000, ipchange_handler, NULL);
+ else
+ tmr_cancel(&net.tmr);
+}
+
+
+static int dns_debug(struct re_printf *pf, void *unused)
+{
+ struct sa nsv[4];
+ uint32_t i, nsn;
+ int err;
+
+ (void)unused;
+
+ nsn = ARRAY_SIZE(nsv);
+
+ err = dns_srv_get(NULL, 0, nsv, &nsn);
+ if (err)
+ nsn = 0;
+
+ err = re_hprintf(pf, " DNS Servers: (%u)\n", nsn);
+ for (i=0; i<nsn; i++)
+ err |= re_hprintf(pf, " %u: %J\n", i, &nsv[i]);
+ for (i=0; i<net.nsn; i++)
+ err |= re_hprintf(pf, " %u: %J\n", nsn+i, &net.nsv[i]);
+
+ return err;
+}
+
+
+int net_af(void)
+{
+ return net.af;
+}
+
+
+/**
+ * Print networking debug information
+ *
+ * @param pf Print handler for debug output
+ * @param unused Unused parameter
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int net_debug(struct re_printf *pf, void *unused)
+{
+ int err;
+
+ (void)unused;
+
+ err = re_hprintf(pf, "--- Network debug ---\n");
+ err |= re_hprintf(pf, " Preferred AF: %s\n", net_af2name(net.af));
+ err |= re_hprintf(pf, " Local IPv4: %9s - %j\n",
+ net.ifname, &net.laddr);
+#ifdef HAVE_INET6
+ err |= re_hprintf(pf, " Local IPv6: %9s - %j\n",
+ net.ifname6, &net.laddr6);
+#endif
+
+ err |= net_if_debug(pf, NULL);
+
+ err |= net_rt_debug(pf, NULL);
+
+ err |= dns_debug(pf, NULL);
+
+ return err;
+}
+
+
+/**
+ * Get the local IP Address for a specific Address Family (AF)
+ *
+ * @param af Address Family
+ *
+ * @return Local IP Address
+ */
+const struct sa *net_laddr_af(int af)
+{
+ switch (af) {
+
+ case AF_INET: return &net.laddr;
+#ifdef HAVE_INET6
+ case AF_INET6: return &net.laddr6;
+#endif
+ default: return NULL;
+ }
+}
+
+
+/**
+ * Get the DNS Client
+ *
+ * @return DNS Client
+ */
+struct dnsc *net_dnsc(void)
+{
+ return net.dnsc;
+}
+
+
+/**
+ * Get the network domain name
+ *
+ * @return Network domain
+ */
+const char *net_domain(void)
+{
+ return net.domain[0] ? net.domain : NULL;
+}