]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: net_addr2ip() - Optimize for parsing IPv4 addresses
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Fri, 3 Nov 2017 23:43:41 +0000 (01:43 +0200)
committerAki Tuomi <aki.tuomi@dovecot.fi>
Mon, 6 Nov 2017 07:34:31 +0000 (09:34 +0200)
src/lib/net.c
src/lib/test-net.c

index 1e7763d748a7bb814574db0240da2a9d22834f66..ce24b8bedc91e3011e6b2da726a87077f12c6323 100644 (file)
@@ -892,10 +892,48 @@ const char *net_ip2addr(const struct ip_addr *ip)
        return addr;
 }
 
+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 */
                T_BEGIN {
index 23a90efefa852d277509e04b6c47c793e6af253e..b6b88bc36865623b7f6737565a99050764966796 100644 (file)
@@ -65,12 +65,22 @@ static void test_net_ip2addr(void)
        test_assert(net_addr2ip("127.0.0.1", &ip) == 0 &&
                    ip.family == AF_INET &&
                    ntohl(ip.u.ip4.s_addr) == (0x7f000001));
+       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);