Squashed 'third_party/rawrtc/re/' content from commit f3163ce8b

Change-Id: I6a235e6ac0f03269d951026f9d195da05c40fdab
git-subtree-dir: third_party/rawrtc/re
git-subtree-split: f3163ce8b526a13b35ef71ce4dd6f43585064d8a
diff --git a/src/net/bsd/brt.c b/src/net/bsd/brt.c
new file mode 100644
index 0000000..d30aab4
--- /dev/null
+++ b/src/net/bsd/brt.c
@@ -0,0 +1,101 @@
+/**
+ * @file bsd/brt.c  BSD routing table code
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#include <re_types.h>
+#include <re_fmt.h>
+#include <re_mem.h>
+#include <re_sa.h>
+#include <re_net.h>
+#include <sys/sysctl.h>
+#include <net/route.h>
+#include <net/if.h>
+
+
+/*
+ * See https://github.com/boundary/libdnet/blob/master/src/route-bsd.c
+ */
+
+#ifdef __APPLE__
+#define RT_MSGHDR_ALIGNMENT sizeof(uint32_t)
+#else
+#define RT_MSGHDR_ALIGNMENT sizeof(unsigned long)
+#endif
+
+#define ROUNDUP(a) \
+	((a) > 0						\
+	 ? (1 + (((size_t)(a) - 1) | (RT_MSGHDR_ALIGNMENT - 1))) \
+	 : RT_MSGHDR_ALIGNMENT)
+
+
+int net_rt_list(net_rt_h *rth, void *arg)
+{
+	/* net.route.0.inet.flags.gateway */
+	int mib[] = {CTL_NET, PF_ROUTE, 0, AF_UNSPEC,
+	             NET_RT_FLAGS, RTF_GATEWAY};
+	char ifname[IFNAMSIZ], *buf, *p;
+	struct rt_msghdr *rt;
+	struct sockaddr *sa, *sa_tab[RTAX_MAX];
+	struct sa dst, gw;
+	size_t l;
+	int i, err = 0;
+
+	if (sysctl(mib, sizeof(mib)/sizeof(int), 0, &l, 0, 0) < 0)
+		return errno;
+	if (!l)
+		return ENOENT;
+
+	buf = mem_alloc(l, NULL);
+	if (!buf)
+		return ENOMEM;
+
+	if (sysctl(mib, sizeof(mib)/sizeof(int), buf, &l, 0, 0) < 0) {
+		err = errno;
+		goto out;
+	}
+
+	for (p = buf; p<buf+l; p += rt->rtm_msglen) {
+		rt = (void *)p;  /* buffer is aligned */
+		sa = (struct sockaddr *)(rt + 1);
+
+		if (rt->rtm_type != RTM_GET)
+			continue;
+
+		if (!(rt->rtm_flags & RTF_UP))
+			continue;
+
+		for (i=0; i<RTAX_MAX; i++) {
+
+			if (rt->rtm_addrs & (1 << i)) {
+				sa_tab[i] = sa;
+				sa = (struct sockaddr *)
+					((char *)sa + ROUNDUP(sa->sa_len));
+			}
+			else {
+				sa_tab[i] = NULL;
+			}
+		}
+
+		if ((rt->rtm_addrs & RTA_DST) == RTA_DST) {
+			err = sa_set_sa(&dst, sa_tab[RTAX_DST]);
+			if (err)
+				continue;
+		}
+		if ((rt->rtm_addrs & RTA_GATEWAY) == RTA_GATEWAY) {
+			err = sa_set_sa(&gw, sa_tab[RTAX_GATEWAY]);
+			if (err)
+				continue;
+		}
+
+		if_indextoname(rt->rtm_index, ifname);
+
+		if (rth(ifname, &dst, 0, &gw, arg))
+			break;
+	}
+
+ out:
+	mem_deref(buf);
+
+	return err;
+}
diff --git a/src/net/if.c b/src/net/if.c
new file mode 100644
index 0000000..ed99cbf
--- /dev/null
+++ b/src/net/if.c
@@ -0,0 +1,233 @@
+/**
+ * @file net/if.c  Network interface code
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#include <re_types.h>
+#include <re_fmt.h>
+#include <re_mbuf.h>
+#include <re_sa.h>
+#include <re_net.h>
+
+
+#define DEBUG_MODULE "netif"
+#define DEBUG_LEVEL 5
+#include <re_dbg.h>
+
+
+/** Interface address entry */
+struct ifentry {
+	int af;        /**< Address family */
+	char *ifname;  /**< Interface name */
+	struct sa *ip; /**< IP address     */
+	size_t sz;     /**< Size of buffer */
+	bool found;    /**< Found flag     */
+};
+
+
+static bool if_getname_handler(const char *ifname, const struct sa *sa,
+			       void *arg)
+{
+	struct ifentry *ife = arg;
+
+	if (ife->af != sa_af(sa))
+		return false;
+
+	if (sa_cmp(sa, ife->ip, SA_ADDR)) {
+		str_ncpy(ife->ifname, ifname, ife->sz);
+		ife->found = true;
+		return true;
+	}
+
+	return false;
+}
+
+
+/**
+ * Get the name of the interface for a given IP address
+ *
+ * @param ifname Buffer for returned network interface name
+ * @param sz     Size of buffer
+ * @param af     Address Family
+ * @param ip     Given IP address
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int net_if_getname(char *ifname, size_t sz, int af, const struct sa *ip)
+{
+	struct ifentry ife;
+	int err;
+
+	if (!ifname || !sz || !ip)
+		return EINVAL;
+
+	ife.af     = af;
+	ife.ifname = ifname;
+	ife.ip     = (struct sa *)ip;
+	ife.sz     = sz;
+	ife.found  = false;
+
+	err = net_if_list(if_getname_handler, &ife);
+
+	return ife.found ? err : ENODEV;
+}
+
+
+static bool if_getaddr_handler(const char *ifname,
+			       const struct sa *sa, void *arg)
+{
+	struct ifentry *ife = arg;
+
+	/* Match name of interface? */
+	if (str_isset(ife->ifname) && 0 != str_casecmp(ife->ifname, ifname))
+		return false;
+
+	if (!sa_isset(sa, SA_ADDR))
+		return false;
+
+#if 1
+	/* skip loopback and link-local IP */
+	if (sa_is_loopback(sa) || sa_is_linklocal(sa))
+		return false;
+#endif
+
+	/* Match address family */
+	if (ife->af != sa_af(sa))
+		return false;
+
+	/* Match - copy address */
+	sa_cpy(ife->ip, sa);
+	ife->found = true;
+
+	return ife->found;
+}
+
+
+/**
+ * Get IP address for a given network interface
+ *
+ * @param ifname  Network interface name (optional)
+ * @param af      Address Family
+ * @param ip      Returned IP address
+ *
+ * @return 0 if success, otherwise errorcode
+ *
+ * @deprecated Works for IPv4 only
+ */
+int net_if_getaddr(const char *ifname, int af, struct sa *ip)
+{
+	struct ifentry ife;
+	int err;
+
+	if (!ip)
+		return EINVAL;
+
+	ife.af     = af;
+	ife.ifname = (char *)ifname;
+	ife.ip     = ip;
+	ife.sz     = 0;
+	ife.found  = false;
+
+#ifdef HAVE_GETIFADDRS
+	err = net_getifaddrs(if_getaddr_handler, &ife);
+#else
+	err = net_if_list(if_getaddr_handler, &ife);
+#endif
+
+	return ife.found ? err : ENODEV;
+}
+
+
+static bool if_debug_handler(const char *ifname, const struct sa *sa,
+			     void *arg)
+{
+	struct re_printf *pf = arg;
+
+	(void)re_hprintf(pf, " %10s:  %j\n", ifname, sa);
+
+	return false;
+}
+
+
+/**
+ * Debug network interfaces
+ *
+ * @param pf     Print handler for debug output
+ * @param unused Unused parameter
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int net_if_debug(struct re_printf *pf, void *unused)
+{
+	int err;
+
+	(void)unused;
+
+	err = re_hprintf(pf, "net interfaces:\n");
+
+#ifdef HAVE_GETIFADDRS
+	err |= net_getifaddrs(if_debug_handler, pf);
+#else
+	err |= net_if_list(if_debug_handler, pf);
+#endif
+
+	return err;
+}
+
+
+static bool linklocal_handler(const char *ifname, const struct sa *sa,
+			      void *arg)
+{
+	void **argv = arg;
+	int af = *(int *)argv[1];
+
+	if (argv[0] && 0 != str_casecmp(argv[0], ifname))
+		return false;
+
+	if (af != AF_UNSPEC && af != sa_af(sa))
+		return false;
+
+	if (sa_is_linklocal(sa)) {
+		*((struct sa *)argv[2]) = *sa;
+		return true;
+	}
+
+	return false;
+}
+
+
+/**
+ * Get the Link-local address for a specific network interface
+ *
+ * @param ifname Name of the interface
+ * @param af     Address family
+ * @param ip     Returned link-local address
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int net_if_getlinklocal(const char *ifname, int af, struct sa *ip)
+{
+	struct sa addr;
+	void *argv[3];
+	int err;
+
+	if (!ip)
+		return EINVAL;
+
+	sa_init(&addr, sa_af(ip));
+
+	argv[0] = (void *)ifname;
+	argv[1] = &af;
+	argv[2] = &addr;
+
+	err = net_if_apply(linklocal_handler, argv);
+	if (err)
+		return err;
+
+	if (!sa_isset(&addr, SA_ADDR))
+		return ENOENT;
+
+	*ip = addr;
+
+	return 0;
+}
diff --git a/src/net/ifaddrs.c b/src/net/ifaddrs.c
new file mode 100644
index 0000000..2116bda
--- /dev/null
+++ b/src/net/ifaddrs.c
@@ -0,0 +1,64 @@
+/**
+ * @file ifaddrs.c  Network interface code using getifaddrs().
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#include <unistd.h>
+#include <sys/socket.h>
+#define __USE_MISC 1   /**< Use MISC code */
+#include <net/if.h>
+#include <ifaddrs.h>
+#include <re_types.h>
+#include <re_fmt.h>
+#include <re_sa.h>
+#include <re_net.h>
+
+
+#define DEBUG_MODULE "ifaddrs"
+#define DEBUG_LEVEL 5
+#include <re_dbg.h>
+
+
+/**
+ * Get a list of all network interfaces including name and IP address.
+ * Both IPv4 and IPv6 are supported.
+ *
+ * @param ifh Interface handler, called once per network interface.
+ * @param arg Handler argument.
+ *
+ * @return 0 if success, otherwise errorcode.
+ */
+int net_getifaddrs(net_ifaddr_h *ifh, void *arg)
+{
+	struct ifaddrs *ifa, *ifp;
+	int err;
+
+	if (!ifh)
+		return EINVAL;
+
+	if (0 != getifaddrs(&ifa)) {
+		err = errno;
+		DEBUG_WARNING("getifaddrs: %m\n", err);
+		return err;
+	}
+
+	for (ifp = ifa; ifa; ifa = ifa->ifa_next) {
+		struct sa sa;
+
+		DEBUG_INFO("ifaddr: %10s flags=%08x\n", ifa->ifa_name,
+			   ifa->ifa_flags);
+
+		if (ifa->ifa_flags & IFF_UP) {
+			err = sa_set_sa(&sa, ifa->ifa_addr);
+			if (err)
+				continue;
+
+			if (ifh(ifa->ifa_name, &sa, arg))
+				break;
+		}
+	}
+
+	freeifaddrs(ifp);
+
+	return 0;
+}
diff --git a/src/net/linux/rt.c b/src/net/linux/rt.c
new file mode 100644
index 0000000..2152af1
--- /dev/null
+++ b/src/net/linux/rt.c
@@ -0,0 +1,253 @@
+/**
+ * @file linux/rt.c  Routing table code for Linux. See rtnetlink(7)
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#define _BSD_SOURCE 1
+#define _DEFAULT_SOURCE 1
+#include <string.h>
+#include <unistd.h>
+#define __USE_POSIX 1  /**< Use POSIX flag */
+#include <netdb.h>
+#define __USE_MISC 1
+#include <net/if.h>
+#undef __STRICT_ANSI__
+#include <linux/types.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <re_types.h>
+#include <re_mbuf.h>
+#include <re_fmt.h>
+#include <re_sa.h>
+#include <re_net.h>
+
+
+#define DEBUG_MODULE "linuxrt"
+#define DEBUG_LEVEL 5
+#include <re_dbg.h>
+
+
+/* Override macros to avoid casting alignment warning */
+#undef RTM_RTA
+#define RTM_RTA(r) (void *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct rtmsg)))
+#undef RTA_NEXT
+#define RTA_NEXT(rta, len) ((len) -= RTA_ALIGN((rta)->rta_len), \
+		(void *)(((char *)(rta)) + RTA_ALIGN((rta)->rta_len)))
+#undef NLMSG_NEXT
+#define NLMSG_NEXT(nlh,len)	 ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
+		  (void*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
+
+
+enum {BUFSIZE = 8192};
+
+
+/** Defines a network route */
+struct net_rt {
+	char ifname[IFNAMSIZ];  /**< Interface name                 */
+	struct sa dst;          /**< Destination IP address/network */
+	int dstlen;             /**< Prefix length of destination   */
+	struct sa gw;           /**< Gateway IP address             */
+};
+
+
+static int read_sock(int fd, uint8_t *buf, size_t size, int seq, int pid)
+{
+	struct nlmsghdr *nlhdr;
+	int n = 0, len = 0;
+
+	do {
+		/* Receive response from the kernel */
+		if ((n = recv(fd, buf, size - len, 0)) < 0) {
+			DEBUG_WARNING("SOCK READ: %m\n", errno);
+			return -1;
+		}
+		nlhdr = (struct nlmsghdr *)(void *)buf;
+
+		/* Check if the header is valid */
+		if (0 == NLMSG_OK(nlhdr, (uint32_t)n) ||
+		    NLMSG_ERROR == nlhdr->nlmsg_type) {
+			DEBUG_WARNING("Error in received packet\n");
+			return -1;
+		}
+
+		/* Check if the its the last message */
+		if (NLMSG_DONE == nlhdr->nlmsg_type) {
+			break;
+		}
+		else{
+			/* Else move the pointer to buffer appropriately */
+			buf += n;
+			len += n;
+		}
+
+		/* Check if its a multi part message */
+		if (0 == (nlhdr->nlmsg_flags & NLM_F_MULTI)) {
+			/* return if its not */
+			break;
+		}
+	} while (nlhdr->nlmsg_seq != (uint32_t)seq ||
+		 nlhdr->nlmsg_pid != (uint32_t)pid);
+
+	return len;
+}
+
+
+/* Parse one route */
+static int rt_parse(const struct nlmsghdr *nlhdr, struct net_rt *rt)
+{
+	struct rtmsg *rtmsg;
+	struct rtattr *rtattr;
+	int len;
+
+	rtmsg = (struct rtmsg *)NLMSG_DATA(nlhdr);
+
+	/* If the route does not belong to main routing table then return. */
+	if (RT_TABLE_MAIN != rtmsg->rtm_table)
+		return EINVAL;
+
+	sa_init(&rt->dst, rtmsg->rtm_family);
+	rt->dstlen = rtmsg->rtm_dst_len;
+
+	/* get the rtattr field */
+	rtattr = (struct rtattr *)RTM_RTA(rtmsg);
+	len = RTM_PAYLOAD(nlhdr);
+	for (;RTA_OK(rtattr, len); rtattr = RTA_NEXT(rtattr, len)) {
+
+		switch (rtattr->rta_type) {
+
+		case RTA_OIF:
+			if_indextoname(*(int *)RTA_DATA(rtattr), rt->ifname);
+			break;
+
+		case RTA_GATEWAY:
+			switch (rtmsg->rtm_family) {
+
+			case AF_INET:
+				sa_init(&rt->gw, AF_INET);
+				rt->gw.u.in.sin_addr.s_addr
+					= *(uint32_t *)RTA_DATA(rtattr);
+				break;
+
+#ifdef HAVE_INET6
+			case AF_INET6:
+				sa_set_in6(&rt->gw, RTA_DATA(rtattr), 0);
+				break;
+#endif
+
+			default:
+				DEBUG_WARNING("RTA_DST: unknown family %d\n",
+					      rtmsg->rtm_family);
+				break;
+			}
+			break;
+
+#if 0
+		case RTA_PREFSRC:
+			rt->srcaddr = *(uint32_t *)RTA_DATA(rtattr);
+			break;
+#endif
+
+		case RTA_DST:
+			switch (rtmsg->rtm_family) {
+
+			case AF_INET:
+				sa_init(&rt->dst, AF_INET);
+				rt->dst.u.in.sin_addr.s_addr
+					= *(uint32_t *)RTA_DATA(rtattr);
+				break;
+
+#ifdef HAVE_INET6
+			case AF_INET6:
+				sa_set_in6(&rt->dst, RTA_DATA(rtattr), 0);
+				break;
+#endif
+
+			default:
+				DEBUG_WARNING("RTA_DST: unknown family %d\n",
+					      rtmsg->rtm_family);
+				break;
+			}
+			break;
+		}
+	}
+
+	return 0;
+}
+
+
+/**
+ * List all entries in the routing table
+ *
+ * @param rth Route entry handler
+ * @param arg Handler argument
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int net_rt_list(net_rt_h *rth, void *arg)
+{
+	union {
+		uint8_t buf[BUFSIZE];
+		struct nlmsghdr msg[1];
+	} u;
+	struct nlmsghdr *nlmsg;
+	int sock, len, seq = 0, err = 0;
+
+	if (!rth)
+		return EINVAL;
+
+	/* Create Socket */
+	if ((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0) {
+		DEBUG_WARNING("list: socket(): (%m)\n", errno);
+		return errno;
+	}
+
+	/* Initialize the buffer */
+	memset(u.buf, 0, sizeof(u.buf));
+
+	/* point the header and the msg structure pointers into the buffer */
+	nlmsg = u.msg;
+
+	/* Fill in the nlmsg header*/
+	nlmsg->nlmsg_len   = NLMSG_LENGTH(sizeof(struct rtmsg));
+	nlmsg->nlmsg_type  = RTM_GETROUTE;
+	nlmsg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
+	nlmsg->nlmsg_seq   = seq++;
+	nlmsg->nlmsg_pid   = getpid();
+
+	/* Send the request */
+	if (send(sock, nlmsg, nlmsg->nlmsg_len, 0) < 0) {
+		err = errno;
+		DEBUG_WARNING("list: write to socket failed (%m)\n", err);
+		goto out;
+	}
+
+	/* Read the response */
+	if ((len = read_sock(sock, u.buf, sizeof(u.buf), seq, getpid())) < 0) {
+		err = errno;
+		DEBUG_WARNING("list: read from socket failed (%m)\n", err);
+		goto out;
+	}
+
+	/* Parse and print the response */
+	for (;NLMSG_OK(nlmsg,(uint32_t)len);nlmsg = NLMSG_NEXT(nlmsg,len)) {
+		struct net_rt rt;
+
+		memset(&rt, 0, sizeof(struct net_rt));
+		if (0 != rt_parse(nlmsg, &rt))
+			continue;
+
+#ifdef HAVE_INET6
+		if (AF_INET6 == sa_af(&rt.dst)
+		    && IN6_IS_ADDR_UNSPECIFIED(&rt.dst.u.in6.sin6_addr))
+			continue;
+#endif
+
+		if (rth(rt.ifname, &rt.dst, rt.dstlen, &rt.gw, arg))
+			break;
+	}
+
+ out:
+	(void)close(sock);
+
+	return err;
+}
diff --git a/src/net/mod.mk b/src/net/mod.mk
new file mode 100644
index 0000000..8f12899
--- /dev/null
+++ b/src/net/mod.mk
@@ -0,0 +1,41 @@
+#
+# mod.mk
+#
+# Copyright (C) 2010 Creytiv.com
+#
+
+# Generic files
+SRCS	+= net/if.c
+SRCS	+= net/net.c
+SRCS	+= net/netstr.c
+SRCS	+= net/rt.c
+SRCS	+= net/sock.c
+SRCS	+= net/sockopt.c
+
+
+# Platform dependant files
+ifneq ($(OS),win32)
+SRCS	+= net/posix/pif.c
+else
+SRCS	+= net/win32/wif.c
+endif
+
+
+# Routing
+ifeq ($(OS),linux)
+SRCS	+= net/linux/rt.c
+CFLAGS  += -DHAVE_ROUTE_LIST
+else
+
+ifneq ($(HAVE_SYS_SYSCTL_H),)
+ifneq ($(HAVE_NET_ROUTE_H),)
+SRCS	+= net/bsd/brt.c
+CFLAGS  += -DHAVE_ROUTE_LIST
+endif
+endif
+
+endif
+
+ifdef HAVE_GETIFADDRS
+SRCS	+= net/ifaddrs.c
+endif
diff --git a/src/net/net.c b/src/net/net.c
new file mode 100644
index 0000000..0978b1b
--- /dev/null
+++ b/src/net/net.c
@@ -0,0 +1,157 @@
+/**
+ * @file net.c  Networking code.
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#define _BSD_SOURCE 1
+#define _DEFAULT_SOURCE 1
+#include <stdlib.h>
+#include <string.h>
+#if !defined(WIN32)
+#define __USE_BSD 1  /**< Use BSD code */
+#include <unistd.h>
+#include <netdb.h>
+#endif
+#include <re_types.h>
+#include <re_fmt.h>
+#include <re_mbuf.h>
+#include <re_sa.h>
+#include <re_net.h>
+
+
+#define DEBUG_MODULE "net"
+#define DEBUG_LEVEL 5
+#include <re_dbg.h>
+
+
+/**
+ * Get the IP address of the host
+ *
+ * @param af  Address Family
+ * @param ip  Returned IP address
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int net_hostaddr(int af, struct sa *ip)
+{
+	char hostname[256];
+	struct in_addr in;
+	struct hostent *he;
+
+	if (-1 == gethostname(hostname, sizeof(hostname)))
+		return errno;
+
+	he = gethostbyname(hostname);
+	if (!he)
+		return ENOENT;
+
+	if (af != he->h_addrtype)
+		return EAFNOSUPPORT;
+
+	/* Get the first entry */
+	memcpy(&in, he->h_addr_list[0], sizeof(in));
+	sa_set_in(ip, ntohl(in.s_addr), 0);
+
+	return 0;
+}
+
+
+/**
+ * Get the default source IP address
+ *
+ * @param af  Address Family
+ * @param ip  Returned IP address
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int net_default_source_addr_get(int af, struct sa *ip)
+{
+#if defined(WIN32)
+	return net_hostaddr(af, ip);
+#else
+	char ifname[64] = "";
+
+#ifdef HAVE_ROUTE_LIST
+	/* Get interface with default route */
+	(void)net_rt_default_get(af, ifname, sizeof(ifname));
+#endif
+
+	/* First try with default interface */
+	if (0 == net_if_getaddr(ifname, af, ip))
+		return 0;
+
+	/* Then try first real IP */
+	if (0 == net_if_getaddr(NULL, af, ip))
+		return 0;
+
+	return net_if_getaddr4(ifname, af, ip);
+#endif
+}
+
+
+/**
+ * Get a list of all network interfaces including name and IP address.
+ * Both IPv4 and IPv6 are supported
+ *
+ * @param ifh Interface handler, called once per network interface
+ * @param arg Handler argument
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int net_if_apply(net_ifaddr_h *ifh, void *arg)
+{
+#ifdef HAVE_GETIFADDRS
+	return net_getifaddrs(ifh, arg);
+#else
+	return net_if_list(ifh, arg);
+#endif
+}
+
+
+static bool net_rt_handler(const char *ifname, const struct sa *dst,
+			   int dstlen, const struct sa *gw, void *arg)
+{
+	void **argv = arg;
+	struct sa *ip = argv[1];
+	(void)dst;
+	(void)dstlen;
+
+	if (0 == str_cmp(ifname, argv[0])) {
+		*ip = *gw;
+		return true;
+	}
+
+	return false;
+}
+
+
+/**
+ * Get the IP-address of the default gateway
+ *
+ * @param af  Address Family
+ * @param gw  Returned Gateway address
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int net_default_gateway_get(int af, struct sa *gw)
+{
+	char ifname[64];
+	void *argv[2];
+	int err;
+
+	if (!af || !gw)
+		return EINVAL;
+
+	err = net_rt_default_get(af, ifname, sizeof(ifname));
+	if (err)
+		return err;
+
+	argv[0] = ifname;
+	argv[1] = gw;
+
+	err = net_rt_list(net_rt_handler, argv);
+	if (err)
+		return err;
+
+	return 0;
+}
diff --git a/src/net/netstr.c b/src/net/netstr.c
new file mode 100644
index 0000000..3f356d3
--- /dev/null
+++ b/src/net/netstr.c
@@ -0,0 +1,50 @@
+/**
+ * @file netstr.c  Network strings
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#include <re_types.h>
+#include <re_fmt.h>
+#include <re_net.h>
+
+
+/**
+ * Get the name of a protocol
+ *
+ * @param proto Protocol
+ *
+ * @return Protocol name
+ */
+const char *net_proto2name(int proto)
+{
+	switch (proto) {
+
+	case IPPROTO_UDP:     return "UDP";
+	case IPPROTO_TCP:     return "TCP";
+#ifdef IPPROTO_SCTP
+	case IPPROTO_SCTP:    return "SCTP";
+#endif
+	default:              return "???";
+	}
+}
+
+
+/**
+ * Get the name of a address family
+ *
+ * @param af Address family
+ *
+ * @return Address family name
+ */
+const char *net_af2name(int af)
+{
+	switch (af) {
+
+	case AF_UNSPEC:    return "AF_UNSPEC";
+	case AF_INET:      return "AF_INET";
+#ifdef HAVE_INET6
+	case AF_INET6:     return "AF_INET6";
+#endif
+	default:           return "???";
+	}
+}
diff --git a/src/net/posix/pif.c b/src/net/posix/pif.c
new file mode 100644
index 0000000..17e93ab
--- /dev/null
+++ b/src/net/posix/pif.c
@@ -0,0 +1,167 @@
+/**
+ * @file posix/pif.c  POSIX network interface code
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#define __USE_POSIX 1  /**< Use POSIX code */
+#define __USE_XOPEN2K 1/**< Use POSIX.1:2001 code */
+#include <netdb.h>
+#define __USE_MISC 1   /**< Use MISC code */
+#include <net/if.h>
+#include <arpa/inet.h>
+/*#include <net/if_arp.h>*/
+#ifdef __sun
+#include <sys/sockio.h>
+#endif
+#include <re_types.h>
+#include <re_fmt.h>
+#include <re_mbuf.h>
+#include <re_sa.h>
+#include <re_net.h>
+
+
+#define DEBUG_MODULE "posixif"
+#define DEBUG_LEVEL 5
+#include <re_dbg.h>
+
+
+/**
+ * Get IP address for a given network interface
+ *
+ * @param ifname  Network interface name
+ * @param af      Address Family
+ * @param ip      Returned IP address
+ *
+ * @return 0 if success, otherwise errorcode
+ *
+ * @deprecated Works for IPv4 only
+ */
+int net_if_getaddr4(const char *ifname, int af, struct sa *ip)
+{
+	struct addrinfo hints, *res, *r;
+	int error, err;
+
+	if (AF_INET != af)
+		return EAFNOSUPPORT;
+
+	memset(&hints, 0, sizeof(hints));
+	/* set-up hints structure */
+	hints.ai_family   = PF_UNSPEC;
+	hints.ai_flags    = AI_PASSIVE;
+	hints.ai_socktype = SOCK_DGRAM;
+	error = getaddrinfo(NULL, "0", &hints, &res);
+	if (error) {
+		DEBUG_WARNING("get_ifaddr: getaddrinfo(): %s\n",
+			      gai_strerror(error));
+		return EADDRNOTAVAIL;
+	}
+
+	err = ENOENT;
+	for (r = res; r; r = r->ai_next) {
+		struct ifreq ifrr;
+		int fd = -1;
+
+		fd = socket(r->ai_family, SOCK_DGRAM, 0);
+		if (fd < 0) {
+			continue;
+		}
+
+		ifrr.ifr_addr.sa_family = r->ai_family;
+		str_ncpy(ifrr.ifr_name, ifname, sizeof(ifrr.ifr_name));
+
+		if (ioctl(fd, SIOCGIFADDR, &ifrr) < 0) {
+			err = errno;
+			goto next;
+		}
+
+		err = sa_set_sa(ip, &ifrr.ifr_ifru.ifru_addr);
+
+	next:
+		(void)close(fd);
+	}
+
+	freeaddrinfo(res);
+	return err;
+}
+
+
+/**
+ * Enumerate all network interfaces
+ *
+ * @param ifh Interface handler
+ * @param arg Handler argument
+ *
+ * @return 0 if success, otherwise errorcode
+ *
+ * @deprecated Works for IPv4 only
+ */
+int net_if_list(net_ifaddr_h *ifh, void *arg)
+{
+	struct ifreq ifrv[32], *ifr;
+	struct ifconf ifc;
+	int sockfd = -1;
+	int err = 0;
+
+	if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) {
+		err = errno;
+		DEBUG_WARNING("interface list: socket(): (%m)\n", err);
+		goto out;
+	}
+
+	ifc.ifc_len = sizeof(ifrv);
+	ifc.ifc_req = ifrv;
+
+	if (0 != ioctl(sockfd, SIOCGIFCONF, &ifc)) {
+		err = errno;
+		DEBUG_WARNING("interface list: ioctl SIOCFIFCONF: %m\n", err);
+		goto out;
+	}
+
+	for (ifr = ifc.ifc_req;
+	     (char *)ifr < ((char *)ifc.ifc_buf + ifc.ifc_len);
+	     ++ifr) {
+		struct ifreq ifrr;
+		struct sa sa;
+
+		if (ifr->ifr_addr.sa_data == (ifr+1)->ifr_addr.sa_data)
+			continue;  /* duplicate, skip it */
+
+		if (ioctl(sockfd, SIOCGIFFLAGS, ifr))
+			continue;  /* failed to get flags, skip it */
+
+#if 0
+		if (ifr->ifr_flags & IFF_LOOPBACK)
+			continue;
+#endif
+
+		if (!(ifr->ifr_flags & IFF_UP))
+			continue;
+
+		ifrr.ifr_addr.sa_family = AF_INET;
+		str_ncpy(ifrr.ifr_name, ifr->ifr_name, sizeof(ifrr.ifr_name));
+
+		if (ioctl(sockfd, SIOCGIFADDR, &ifrr) < 0) {
+			err = errno;
+			continue;
+		}
+
+		err = sa_set_sa(&sa, &ifrr.ifr_ifru.ifru_addr);
+		if (err) {
+			DEBUG_WARNING("if_list: sa_set_sa %m\n", err);
+			break;
+		}
+
+		if (ifh && ifh(ifr->ifr_name, &sa, arg))
+			break;
+	}
+
+ out:
+	if (sockfd >= 0)
+		(void)close(sockfd);
+
+	return err;
+}
diff --git a/src/net/rt.c b/src/net/rt.c
new file mode 100644
index 0000000..f5d2ef5
--- /dev/null
+++ b/src/net/rt.c
@@ -0,0 +1,158 @@
+/**
+ * @file net/rt.c  Generic routing table code
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#define _BSD_SOURCE 1
+#define _DEFAULT_SOURCE 1
+#include <re_types.h>
+#include <re_fmt.h>
+#include <re_mbuf.h>
+#include <re_sa.h>
+#include <re_net.h>
+
+
+struct net_rt {
+	int af;
+	char *ifname;
+	size_t size;
+	int prefix;
+};
+
+
+static bool rt_debug_handler(const char *ifname, const struct sa *dst,
+			     int dstlen, const struct sa *gw, void *arg)
+{
+	char addr[64];
+	struct re_printf *pf = arg;
+	int err = 0;
+
+	(void)re_snprintf(addr, sizeof(addr), "%j/%d", dst, dstlen);
+
+	err |= re_hprintf(pf, " %-44s", addr);
+	err |= re_hprintf(pf, "%-40j", gw);
+	err |= re_hprintf(pf, " %-15s ", ifname);
+
+#ifdef HAVE_INET6
+	if (AF_INET6 == sa_af(dst)) {
+		const struct sockaddr_in6 *sin6 = &dst->u.in6;
+		const struct in6_addr *in6 = &sin6->sin6_addr;
+
+		if (IN6_IS_ADDR_MULTICAST(in6))
+			err |= re_hprintf(pf, " MULTICAST");
+		if (IN6_IS_ADDR_LINKLOCAL(in6))
+			err |= re_hprintf(pf, " LINKLOCAL");
+		if (IN6_IS_ADDR_SITELOCAL(in6))
+			err |= re_hprintf(pf, " SITELOCAL");
+	}
+#endif
+
+	err |= re_hprintf(pf, "\n");
+
+	return 0 != err;
+}
+
+
+/**
+ * Dump the routing table
+ *
+ * @param pf     Print function for output
+ * @param unused Unused parameter
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int net_rt_debug(struct re_printf *pf, void *unused)
+{
+	int err = 0;
+
+	(void)unused;
+
+	err |= re_hprintf(pf, "net routes:\n");
+
+	err |= re_hprintf(pf, " Destination                                 "
+			  "Next Hop"
+			  "                                 Iface           "
+			  "Type\n");
+
+	err |= net_rt_list(rt_debug_handler, pf);
+
+	return err;
+}
+
+
+static bool rt_default_get_handler(const char *_ifname, const struct sa *dst,
+				   int dstlen, const struct sa *gw, void *arg)
+{
+	struct net_rt *rt = arg;
+
+	(void)dstlen;
+	(void)gw;
+
+	if (sa_af(dst) != rt->af)
+		return false;
+
+	switch (rt->af) {
+
+	case AF_INET:
+		if (0 == sa_in(dst)) {
+			str_ncpy(rt->ifname, _ifname, rt->size);
+			return true;
+		}
+		break;
+
+#ifdef HAVE_INET6
+	case AF_INET6:
+		if (IN6_IS_ADDR_MULTICAST(&dst->u.in6.sin6_addr))
+			return false;
+		if (IN6_IS_ADDR_LINKLOCAL(&dst->u.in6.sin6_addr))
+			return false;
+
+		if (dstlen < rt->prefix) {
+			rt->prefix = dstlen;
+			str_ncpy(rt->ifname, _ifname, rt->size);
+			return false;
+		}
+		break;
+#endif
+	}
+
+	return false;
+}
+
+
+/**
+ * Get the interface name of the default route
+ *
+ * @param af     Address family
+ * @param ifname Buffer for returned interface name
+ * @param size   Size of buffer
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int net_rt_default_get(int af, char *ifname, size_t size)
+{
+	struct net_rt rt;
+	int err;
+
+	rt.af     = af;
+	rt.ifname = ifname;
+	rt.size   = size;
+	rt.prefix = 256;
+
+	err = net_rt_list(rt_default_get_handler, &rt);
+	if (err)
+		return err;
+
+	return '\0' != ifname[0] ? 0 : EINVAL;
+}
+
+
+#ifndef HAVE_ROUTE_LIST
+/* We must provide a stub */
+int net_rt_list(net_rt_h *rth, void *arg)
+{
+	(void)rth;
+	(void)arg;
+	return ENOSYS;
+}
+#endif
diff --git a/src/net/sock.c b/src/net/sock.c
new file mode 100644
index 0000000..7b74dee
--- /dev/null
+++ b/src/net/sock.c
@@ -0,0 +1,91 @@
+/**
+ * @file net/sock.c  Networking sockets code
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#include <re_types.h>
+#include <re_fmt.h>
+#include <re_mbuf.h>
+#include <re_net.h>
+
+
+#define DEBUG_MODULE "netsock"
+#define DEBUG_LEVEL 5
+#include <re_dbg.h>
+
+
+static bool inited = false;
+
+
+#ifdef WIN32
+static int wsa_init(void)
+{
+	WORD wVersionRequested = MAKEWORD(2, 2);
+	WSADATA wsaData;
+	int err;
+
+	err = WSAStartup(wVersionRequested, &wsaData);
+	if (err != 0) {
+		DEBUG_WARNING("Could not load winsock (%m)\n", err);
+		return err;
+	}
+
+	/* Confirm that the WinSock DLL supports 2.2.*/
+	/* Note that if the DLL supports versions greater    */
+	/* than 2.2 in addition to 2.2, it will still return */
+	/* 2.2 in wVersion since that is the version we      */
+	/* requested.                                        */
+	if (LOBYTE(wsaData.wVersion) != 2 ||
+	    HIBYTE(wsaData.wVersion) != 2 ) {
+		WSACleanup();
+		DEBUG_WARNING("Bad winsock verion (%d.%d)\n",
+			      HIBYTE(wsaData.wVersion),
+			      LOBYTE(wsaData.wVersion));
+		return EINVAL;
+	}
+
+	return 0;
+}
+#endif
+
+
+/**
+ * Initialise network sockets
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int net_sock_init(void)
+{
+	int err = 0;
+
+	DEBUG_INFO("sock init: inited=%d\n", inited);
+
+	if (inited)
+		return 0;
+
+#ifdef WIN32
+	err = wsa_init();
+#endif
+
+	inited = true;
+
+	return err;
+}
+
+
+/**
+ * Cleanup network sockets
+ */
+void net_sock_close(void)
+{
+#ifdef WIN32
+	const int err = WSACleanup();
+	if (0 != err) {
+		DEBUG_WARNING("sock close: WSACleanup (%d)\n", err);
+	}
+#endif
+
+	inited = false;
+
+	DEBUG_INFO("sock close\n");
+}
diff --git a/src/net/sockopt.c b/src/net/sockopt.c
new file mode 100644
index 0000000..2385a69
--- /dev/null
+++ b/src/net/sockopt.c
@@ -0,0 +1,112 @@
+/**
+ * @file sockopt.c  Networking socket options
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <re_types.h>
+#include <re_fmt.h>
+#include <re_net.h>
+
+
+#define DEBUG_MODULE "sockopt"
+#define DEBUG_LEVEL 5
+#include <re_dbg.h>
+
+
+/** Platform independent buffer type cast */
+#ifdef WIN32
+#define BUF_CAST (char *)
+#else
+#define BUF_CAST
+#endif
+
+
+/**
+ * Set socket option blocking or non-blocking
+ *
+ * @param fd       Socket file descriptor
+ * @param blocking true for blocking, false for non-blocking
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int net_sockopt_blocking_set(int fd, bool blocking)
+{
+#ifdef WIN32
+	unsigned long noblock = !blocking;
+	int err = 0;
+
+	if (0 != ioctlsocket(fd, FIONBIO, &noblock)) {
+		err = WSAGetLastError();
+		DEBUG_WARNING("nonblock set: fd=%d err=%d (%m)\n",
+			      fd, err, err);
+	}
+	return err;
+#else
+	int flags;
+	int err = 0;
+
+	flags = fcntl(fd, F_GETFL);
+	if (-1 == flags) {
+		err = errno;
+		DEBUG_WARNING("sockopt set: fnctl F_GETFL: (%m)\n", err);
+		goto out;
+	}
+
+	if (blocking)
+		flags &= ~O_NONBLOCK;
+	else
+		flags |= O_NONBLOCK;
+
+	if (-1 == fcntl(fd, F_SETFL, flags)) {
+		err = errno;
+		DEBUG_WARNING("sockopt set: fcntl F_SETFL non-block (%m)\n",
+			      err);
+	}
+
+ out:
+	return err;
+#endif
+}
+
+
+/**
+ * Set socket option to reuse address and port
+ *
+ * @param fd     Socket file descriptor
+ * @param reuse  true for reuse, false for no reuse
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int net_sockopt_reuse_set(int fd, bool reuse)
+{
+	int r = reuse;
+
+#ifdef SO_REUSEADDR
+	if (-1 == setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+			     BUF_CAST &r, sizeof(r))) {
+		DEBUG_WARNING("SO_REUSEADDR: %m\n", errno);
+		return errno;
+	}
+#endif
+
+#ifdef SO_REUSEPORT
+	if (-1 == setsockopt(fd, SOL_SOCKET, SO_REUSEPORT,
+			     BUF_CAST &r, sizeof(r))) {
+		DEBUG_INFO("SO_REUSEPORT: %m\n", errno);
+		return errno;
+	}
+#endif
+
+#if !defined(SO_REUSEADDR) && !defined(SO_REUSEPORT)
+	(void)r;
+	(void)fd;
+	(void)reuse;
+	return ENOSYS;
+#else
+	return 0;
+#endif
+}
diff --git a/src/net/win32/wif.c b/src/net/win32/wif.c
new file mode 100644
index 0000000..f24894f
--- /dev/null
+++ b/src/net/win32/wif.c
@@ -0,0 +1,127 @@
+/**
+ * @file wif.c  Windows network interface code
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#include <winsock2.h>
+#include <iphlpapi.h>
+#include <re_types.h>
+#include <re_fmt.h>
+#include <re_net.h>
+#include <re_sa.h>
+
+
+#define DEBUG_MODULE "wif"
+#define DEBUG_LEVEL 5
+#include <re_dbg.h>
+
+
+/**
+ * List interfaces using GetAdaptersAddresses, which handles both
+ * IPv4 and IPv6 address families.
+ *
+ * This is available from Windows XP and Windows Server 2003
+ */
+static int if_list_gaa(net_ifaddr_h *ifh, void *arg)
+{
+	IP_ADAPTER_ADDRESSES addrv[64], *cur;
+	ULONG ret, len = sizeof(addrv);
+	const ULONG flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST;
+	HANDLE hLib;
+	union {
+		FARPROC proc;
+		ULONG (WINAPI *gaa)(ULONG, ULONG, PVOID,
+				    PIP_ADAPTER_ADDRESSES, PULONG);
+	} u;
+	bool stop = false;
+	int err = 0;
+
+	hLib = LoadLibrary(TEXT("iphlpapi.dll"));
+	if (!hLib)
+		return ENOSYS;
+
+	u.proc = GetProcAddress(hLib, TEXT("GetAdaptersAddresses"));
+	if (!u.proc) {
+		err = ENOSYS;
+		goto out;
+	}
+
+	ret = (*u.gaa)(AF_UNSPEC, flags, NULL, addrv, &len);
+	if (ret != ERROR_SUCCESS) {
+		DEBUG_WARNING("if_list: GetAdaptersAddresses ret=%u\n", ret);
+		err = ENODEV;
+		goto out;
+	}
+
+	for (cur = addrv; cur && !stop; cur = cur->Next) {
+		PIP_ADAPTER_UNICAST_ADDRESS ip;
+
+		/* an interface can have many IP-addresses */
+		for (ip = cur->FirstUnicastAddress; ip; ip = ip->Next) {
+			struct sa sa;
+
+			sa_set_sa(&sa, ip->Address.lpSockaddr);
+
+			if (ifh && ifh(cur->AdapterName, &sa, arg)) {
+				stop = true;
+				break;
+			}
+		}
+	}
+
+ out:
+	FreeLibrary(hLib);
+
+	return err;
+}
+
+
+/**
+ * List interfaces using GetAdaptersInfo, which handles only IPv4 family.
+ *
+ * This is available from Windows 2000, and also works under Wine.
+ */
+static int if_list_gai(net_ifaddr_h *ifh, void *arg)
+{
+	IP_ADAPTER_INFO info[32];
+	PIP_ADAPTER_INFO p = info;
+	ULONG ulOutBufLen = sizeof(info);
+	DWORD ret;
+
+	ret = GetAdaptersInfo(info, &ulOutBufLen);
+	if (ret != ERROR_SUCCESS) {
+		DEBUG_WARNING("if_list: GetAdaptersInfo ret=%u\n", ret);
+		return ENODEV;
+	}
+
+	for (p = info; p; p = p->Next) {
+		struct sa sa;
+
+		if (sa_set_str(&sa, p->IpAddressList.IpAddress.String, 0))
+			continue;
+
+		if (ifh && ifh(p->AdapterName, &sa, arg))
+			break;
+	}
+
+	return 0;
+}
+
+
+/**
+ * Enumerate all network interfaces
+ *
+ * @param ifh Interface handler
+ * @param arg Handler argument
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int net_if_list(net_ifaddr_h *ifh, void *arg)
+{
+	/* Try both methods .. */
+
+	if (!if_list_gaa(ifh, arg))
+		return 0;
+
+	return if_list_gai(ifh, arg);
+}