changeset 22639:da6cf4b7caf4

lib: net_addr2ip() - Optimize for parsing IPv4 addresses
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Sat, 04 Nov 2017 01:43:41 +0200
parents 7d5634889da8
children cf23a90cd2ca
files src/lib/net.c src/lib/test-net.c
diffstat 2 files changed, 48 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib/net.c	Sat Nov 04 01:42:37 2017 +0200
+++ b/src/lib/net.c	Sat Nov 04 01:43:41 2017 +0200
@@ -952,10 +952,48 @@
 #endif
 }
 
+static bool net_addr2ip_inet4_fast(const char *addr, struct ip_addr *ip)
+{
+	uint8_t *s_addr = (void *)&ip->u.ip4.s_addr;
+	unsigned int i, num;
+
+	if (str_parse_uint(addr, &num, &addr) < 0)
+		return FALSE;
+	if (*addr == '\0' && num <= 0xffffffff) {
+		/* single-number IPv4 address */
+		ip->u.ip4.s_addr = htonl(num);
+		ip->family = AF_INET;
+		return TRUE;
+	}
+
+	/* try to parse as a.b.c.d */
+	i = 0;
+	for (;;) {
+		if (num >= 256)
+			return FALSE;
+		s_addr[i] = num;
+		if (i == 3)
+			break;
+		i++;
+		if (*addr != '.')
+			return FALSE;
+		addr++;
+		if (str_parse_uint(addr, &num, &addr) < 0)
+			return FALSE;
+	}
+	if (*addr != '\0')
+		return FALSE;
+	ip->family = AF_INET;
+	return TRUE;
+}
+
 int net_addr2ip(const char *addr, struct ip_addr *ip)
 {
 	int ret;
 
+	if (net_addr2ip_inet4_fast(addr, ip))
+		return 0;
+
 	if (strchr(addr, ':') != NULL) {
 		/* IPv6 */
 #ifdef HAVE_IPV6
--- a/src/lib/test-net.c	Sat Nov 04 01:42:37 2017 +0200
+++ b/src/lib/test-net.c	Sat Nov 04 01:43:41 2017 +0200
@@ -71,12 +71,22 @@
 		    ip.family == AF_INET &&
 		    ntohl(ip.u.ip4.s_addr) == (0x7f000001));
 #ifdef HAVE_IPV6
+	test_assert(net_addr2ip("2130706433", &ip) == 0 &&
+		    ip.family == AF_INET &&
+		    ntohl(ip.u.ip4.s_addr) == (0x7f000001));
+	test_assert(strcmp(net_ip2addr(&ip), "127.0.0.1") == 0);
+	test_assert(net_addr2ip("255.254.253.252", &ip) == 0 &&
+		    ip.family == AF_INET &&
+		    ntohl(ip.u.ip4.s_addr) == (0xfffefdfc));
+	test_assert(strcmp(net_ip2addr(&ip), "255.254.253.252") == 0);
 	test_assert(net_addr2ip("::5", &ip) == 0 &&
 		    ip.family == AF_INET6 &&
 		    ip.u.ip6.s6_addr[15] == 5);
+	test_assert(strcmp(net_ip2addr(&ip), "::5") == 0);
 	test_assert(net_addr2ip("[::5]", &ip) == 0 &&
 		    ip.family == AF_INET6 &&
 		    ip.u.ip6.s6_addr[15] == 5);
+	test_assert(strcmp(net_ip2addr(&ip), "::5") == 0);
 	ip.family = 123;
 	test_assert(net_addr2ip("abc", &ip) < 0 &&
 		    ip.family == 123);