summaryrefslogtreecommitdiff
path: root/src/net.c
diff options
context:
space:
mode:
authorAlfred E. Heggestad <aeh@db.org>2016-06-06 10:14:12 +0200
committerAlfred E. Heggestad <aeh@db.org>2016-06-06 10:14:12 +0200
commit6910d50e9b1e80fe758b259149012e7e062eecd0 (patch)
treeaecd149deed8ae71349e3b2e626e53f57a9c974a /src/net.c
parent362914f55831f4ad3afd7c0cad8f01f2f8b4892c (diff)
net: make networking code re-entrant
- The network instance is now in struct network and does not use any local/static data - A new top-level struct in baresip.c owns the single instance of struct network it is a long-term goal to remove all local/static data from libbaresip and make it fully re-entrant.
Diffstat (limited to 'src/net.c')
-rw-r--r--src/net.c324
1 files changed, 200 insertions, 124 deletions
diff --git a/src/net.c b/src/net.c
index 02b9cda..7c12580 100644
--- a/src/net.c
+++ b/src/net.c
@@ -1,7 +1,7 @@
/**
- * @file net.c Networking code
+ * @file src/net.c Networking code
*
- * Copyright (C) 2010 Creytiv.com
+ * Copyright (C) 2010 - 2016 Creytiv.com
*/
#include <re.h>
#include <baresip.h>
@@ -11,7 +11,7 @@
#define MAX_NS 8
-static struct {
+struct network {
struct config_net cfg;
struct sa laddr;
char ifname[16];
@@ -28,31 +28,46 @@ static struct {
char domain[64]; /**< DNS domain from network */
net_change_h *ch;
void *arg;
-} net;
+};
-static int net_dns_srv_get(struct sa *srvv, uint32_t *n, bool *from_sys)
+static int net_dnssrv_add(struct network *net, const struct sa *sa)
+{
+ if (!net)
+ return EINVAL;
+
+ if (net->nsn >= ARRAY_SIZE(net->nsv))
+ return E2BIG;
+
+ sa_cpy(&net->nsv[net->nsn++], sa);
+
+ return 0;
+}
+
+
+static int net_dns_srv_get(const struct network *net,
+ struct sa *srvv, uint32_t *n, bool *from_sys)
{
struct sa nsv[MAX_NS];
uint32_t i, nsn = ARRAY_SIZE(nsv);
int err;
- err = dns_srv_get(net.domain, sizeof(net.domain), nsv, &nsn);
+ err = dns_srv_get(NULL, 0, nsv, &nsn);
if (err) {
nsn = 0;
}
- if (net.nsn) {
+ if (net->nsn) {
- if (net.nsn > *n)
+ if (net->nsn > *n)
return E2BIG;
/* Use any configured nameservers */
- for (i=0; i<net.nsn; i++) {
- srvv[i] = net.nsv[i];
+ for (i=0; i<net->nsn; i++) {
+ srvv[i] = net->nsv[i];
}
- *n = net.nsn;
+ *n = net->nsn;
if (from_sys)
*from_sys = false;
@@ -77,7 +92,7 @@ static int net_dns_srv_get(struct sa *srvv, uint32_t *n, bool *from_sys)
/**
* Check for DNS Server updates
*/
-static void dns_refresh(void)
+static void dns_refresh(struct network *net)
{
struct sa nsv[MAX_NS];
uint32_t nsn;
@@ -85,11 +100,11 @@ static void dns_refresh(void)
nsn = ARRAY_SIZE(nsv);
- err = net_dns_srv_get(nsv, &nsn, NULL);
+ err = net_dns_srv_get(net, nsv, &nsn, NULL);
if (err)
return;
- (void)dnsc_srv_set(net.dnsc, nsv, nsn);
+ (void)dnsc_srv_set(net->dnsc, nsv, nsn);
}
@@ -98,16 +113,16 @@ static void dns_refresh(void)
*/
static void ipchange_handler(void *arg)
{
+ struct network *net = arg;
bool change;
- (void)arg;
- tmr_start(&net.tmr, net.interval * 1000, ipchange_handler, NULL);
+ tmr_start(&net->tmr, net->interval * 1000, ipchange_handler, net);
- dns_refresh();
+ dns_refresh(net);
- change = net_check();
- if (change && net.ch) {
- net.ch(net.arg);
+ change = net_check(net);
+ if (change && net->ch) {
+ net->ch(net->arg);
}
}
@@ -115,49 +130,51 @@ static void ipchange_handler(void *arg)
/**
* Check if local IP address(es) changed
*
+ * @param net Network instance
+ *
* @return True if changed, otherwise false
*/
-bool net_check(void)
+bool net_check(struct network *net)
{
- struct sa laddr = net.laddr;
+ struct sa laddr = net->laddr;
#ifdef HAVE_INET6
- struct sa laddr6 = net.laddr6;
+ struct sa laddr6 = net->laddr6;
#endif
bool change = false;
- if (str_isset(net.cfg.ifname)) {
+ if (str_isset(net->cfg.ifname)) {
- (void)net_if_getaddr(net.cfg.ifname, AF_INET, &net.laddr);
+ (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);
+ (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));
+ (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));
+ (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)) {
+ 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);
+ &laddr, &net->laddr);
}
#ifdef HAVE_INET6
- if (sa_isset(&net.laddr6, SA_ADDR) &&
- !sa_cmp(&laddr6, &net.laddr6, SA_ADDR)) {
+ 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);
+ &laddr6, &net->laddr6);
}
#endif
@@ -165,17 +182,17 @@ bool net_check(void)
}
-static int dns_init(void)
+static int dns_init(struct network *net)
{
struct sa nsv[MAX_NS];
uint32_t nsn = ARRAY_SIZE(nsv);
int err;
- err = net_dns_srv_get(nsv, &nsn, NULL);
+ err = net_dns_srv_get(net, nsv, &nsn, NULL);
if (err)
return err;
- return dnsc_alloc(&net.dnsc, NULL, nsv, nsn);
+ return dnsc_alloc(&net->dnsc, NULL, nsv, nsn);
}
@@ -190,20 +207,33 @@ static bool check_ipv6(void)
}
+static void net_destructor(void *data)
+{
+ struct network *net = data;
+
+ tmr_cancel(&net->tmr);
+ mem_deref(net->dnsc);
+}
+
+
/**
* Initialise networking
*
- * @param cfg Network configuration
- * @param af Preferred address family
+ * @param netp Pointer to allocated network instance
+ * @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 net_alloc(struct network **netp, const struct config_net *cfg, int af)
{
+ struct network *net;
+ struct sa nsv[MAX_NS];
+ uint32_t nsn = ARRAY_SIZE(nsv);
char buf4[128] = "", buf6[128] = "";
int err;
- if (!cfg)
+ if (!netp || !cfg)
return EINVAL;
/*
@@ -225,20 +255,38 @@ int net_init(const struct config_net *cfg, int af)
}
#endif
- net.cfg = *cfg;
- net.af = af;
+ net = mem_zalloc(sizeof(*net), net_destructor);
+ if (!net)
+ return ENOMEM;
+
+ net->cfg = *cfg;
+ net->af = af;
+
+ tmr_init(&net->tmr);
- tmr_init(&net.tmr);
+ if (cfg->nsc) {
+ size_t i;
+
+ for (i=0; i<cfg->nsc; i++) {
+
+ err = net_dnssrv_add(net, &cfg->nsv[i]);
+ if (err) {
+ warning("net: failed to add nameserver: %m\n",
+ err);
+ goto out;
+ }
+ }
+ }
/* Initialise DNS resolver */
- err = dns_init();
+ err = dns_init(net);
if (err) {
warning("net: dns_init: %m\n", err);
- return err;
+ goto out;
}
- sa_init(&net.laddr, AF_INET);
- (void)sa_set_str(&net.laddr, "127.0.0.1", 0);
+ sa_init(&net->laddr, AF_INET);
+ (void)sa_set_str(&net->laddr, "127.0.0.1", 0);
if (str_isset(cfg->ifname)) {
@@ -246,10 +294,10 @@ int net_init(const struct config_net *cfg, int af)
info("Binding to interface '%s'\n", cfg->ifname);
- str_ncpy(net.ifname, cfg->ifname, sizeof(net.ifname));
+ str_ncpy(net->ifname, cfg->ifname, sizeof(net->ifname));
err = net_if_getaddr(cfg->ifname,
- AF_INET, &net.laddr);
+ AF_INET, &net->laddr);
if (err) {
info("net: %s: could not get IPv4 address (%m)\n",
cfg->ifname, err);
@@ -258,11 +306,11 @@ int net_init(const struct config_net *cfg, int af)
got_it = true;
#ifdef HAVE_INET6
- str_ncpy(net.ifname6, cfg->ifname,
- sizeof(net.ifname6));
+ str_ncpy(net->ifname6, cfg->ifname,
+ sizeof(net->ifname6));
err = net_if_getaddr(cfg->ifname,
- AF_INET6, &net.laddr6);
+ AF_INET6, &net->laddr6);
if (err) {
info("net: %s: could not get IPv6 address (%m)\n",
cfg->ifname, err);
@@ -275,77 +323,72 @@ int net_init(const struct config_net *cfg, int af)
else {
warning("net: %s: could not get network address\n",
cfg->ifname);
- return EADDRNOTAVAIL;
+ err = EADDRNOTAVAIL;
+ goto out;
}
}
else {
- (void)net_default_source_addr_get(AF_INET, &net.laddr);
- (void)net_rt_default_get(AF_INET, net.ifname,
- sizeof(net.ifname));
+ (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);
+ 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));
+ (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)) {
+ if (sa_isset(&net->laddr, SA_ADDR)) {
re_snprintf(buf4, sizeof(buf4), " IPv4=%s:%j",
- net.ifname, &net.laddr);
+ net->ifname, &net->laddr);
}
#ifdef HAVE_INET6
- if (sa_isset(&net.laddr6, SA_ADDR)) {
+ if (sa_isset(&net->laddr6, SA_ADDR)) {
re_snprintf(buf6, sizeof(buf6), " IPv6=%s:%j",
- net.ifname6, &net.laddr6);
+ net->ifname6, &net->laddr6);
}
#endif
+
+ (void)dns_srv_get(net->domain, sizeof(net->domain), nsv, &nsn);
+
info("Local network address: %s %s\n",
buf4, buf6);
+ out:
+ if (err)
+ mem_deref(net);
+ else
+ *netp = net;
+
return err;
}
/**
- * Reset the DNS resolver
+ * Use a specific DNS server
+ *
+ * @param net Network instance
+ * @param ns DNS Server IP address and port
*
* @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)
+int net_use_nameserver(struct network *net, const struct sa *ns)
{
- net.dnsc = mem_deref(net.dnsc);
- tmr_cancel(&net.tmr);
- net.nsn = 0;
-}
+ struct dnsc *dnsc;
+ int err;
+ if (!net || !ns)
+ return EINVAL;
-/**
- * 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;
+ err = dnsc_alloc(&dnsc, NULL, ns, 1);
+ if (err)
+ return err;
- sa_cpy(&net.nsv[net.nsn++], sa);
+ mem_deref(net->dnsc);
+ net->dnsc = dnsc;
return 0;
}
@@ -354,33 +397,47 @@ int net_dnssrv_add(const struct sa *sa)
/**
* Check for networking changes with a regular interval
*
+ * @param net Network instance
* @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)
+void net_change(struct network *net, uint32_t interval,
+ net_change_h *ch, void *arg)
{
- net.interval = interval;
- net.ch = ch;
- net.arg = arg;
+ if (!net)
+ return;
+
+ net->interval = interval;
+ net->ch = ch;
+ net->arg = arg;
if (interval)
- tmr_start(&net.tmr, interval * 1000, ipchange_handler, NULL);
+ tmr_start(&net->tmr, interval * 1000, ipchange_handler, net);
else
- tmr_cancel(&net.tmr);
+ tmr_cancel(&net->tmr);
+}
+
+
+void net_force_change(struct network *net)
+{
+ if (net && net->ch) {
+ net->ch(net->arg);
+ }
}
-static int dns_debug(struct re_printf *pf, void *unused)
+static int dns_debug(struct re_printf *pf, const struct network *net)
{
struct sa nsv[MAX_NS];
uint32_t i, nsn = ARRAY_SIZE(nsv);
bool from_sys = false;
int err;
- (void)unused;
+ if (!net)
+ return 0;
- err = net_dns_srv_get(nsv, &nsn, &from_sys);
+ err = net_dns_srv_get(net, nsv, &nsn, &from_sys);
if (err)
nsn = 0;
@@ -393,9 +450,12 @@ static int dns_debug(struct re_printf *pf, void *unused)
}
-int net_af(void)
+int net_af(const struct network *net)
{
- return net.af;
+ if (!net)
+ return AF_UNSPEC;
+
+ return net->af;
}
@@ -403,30 +463,32 @@ int net_af(void)
* Print networking debug information
*
* @param pf Print handler for debug output
- * @param unused Unused parameter
+ * @param net Network instance
*
* @return 0 if success, otherwise errorcode
*/
-int net_debug(struct re_printf *pf, void *unused)
+int net_debug(struct re_printf *pf, const struct network *net)
{
int err;
- (void)unused;
+ if (!net)
+ return 0;
err = re_hprintf(pf, "--- Network debug ---\n");
- err |= re_hprintf(pf, " Preferred AF: %s\n", net_af2name(net.af));
+ 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);
+ net->ifname, &net->laddr);
#ifdef HAVE_INET6
err |= re_hprintf(pf, " Local IPv6: %9s - %j\n",
- net.ifname6, &net.laddr6);
+ net->ifname6, &net->laddr6);
#endif
+ err |= re_hprintf(pf, " Domain: %s\n", net->domain);
err |= net_if_debug(pf, NULL);
err |= net_rt_debug(pf, NULL);
- err |= dns_debug(pf, NULL);
+ err |= dns_debug(pf, net);
return err;
}
@@ -435,17 +497,21 @@ int net_debug(struct re_printf *pf, void *unused)
/**
* Get the local IP Address for a specific Address Family (AF)
*
- * @param af Address Family
+ * @param net Network instance
+ * @param af Address Family
*
* @return Local IP Address
*/
-const struct sa *net_laddr_af(int af)
+const struct sa *net_laddr_af(const struct network *net, int af)
{
+ if (!net)
+ return NULL;
+
switch (af) {
- case AF_INET: return &net.laddr;
+ case AF_INET: return &net->laddr;
#ifdef HAVE_INET6
- case AF_INET6: return &net.laddr6;
+ case AF_INET6: return &net->laddr6;
#endif
default: return NULL;
}
@@ -455,20 +521,30 @@ const struct sa *net_laddr_af(int af)
/**
* Get the DNS Client
*
+ * @param net Network instance
+ *
* @return DNS Client
*/
-struct dnsc *net_dnsc(void)
+struct dnsc *net_dnsc(const struct network *net)
{
- return net.dnsc;
+ if (!net)
+ return NULL;
+
+ return net->dnsc;
}
/**
* Get the network domain name
*
+ * @param net Network instance
+ *
* @return Network domain
*/
-const char *net_domain(void)
+const char *net_domain(const struct network *net)
{
- return net.domain[0] ? net.domain : NULL;
+ if (!net)
+ return NULL;
+
+ return net->domain[0] ? net->domain : NULL;
}