Mercurial > prosody-hg
comparison util/ip.lua @ 13431:4698f1e36e02
util.ip: Remove ip.bits and related code, switch to more efficient strbitop
100,000 iterations of match() on my laptop from 3.5s -> 0.5s.
| author | Matthew Wild <mwild1@gmail.com> |
|---|---|
| date | Fri, 23 Feb 2024 12:14:51 +0000 |
| parents | d10957394a3c |
| children |
comparison
equal
deleted
inserted
replaced
| 13430:1a5e3cf037f6 | 13431:4698f1e36e02 |
|---|---|
| 4 -- This project is MIT/X11 licensed. Please see the | 4 -- This project is MIT/X11 licensed. Please see the |
| 5 -- COPYING file in the source package for more information. | 5 -- COPYING file in the source package for more information. |
| 6 -- | 6 -- |
| 7 | 7 |
| 8 local net = require "prosody.util.net"; | 8 local net = require "prosody.util.net"; |
| 9 local hex = require "prosody.util.hex"; | 9 local strbit = require "prosody.util.strbitop"; |
| 10 | 10 |
| 11 local ip_methods = {}; | 11 local ip_methods = {}; |
| 12 | 12 |
| 13 local ip_mt = { | 13 local ip_mt = { |
| 14 __index = function (ip, key) | 14 __index = function (ip, key) |
| 25 -- Lua 5.3+ calls this if both operands are tables, even if metatables differ | 25 -- Lua 5.3+ calls this if both operands are tables, even if metatables differ |
| 26 return false; | 26 return false; |
| 27 end | 27 end |
| 28 return ipA.packed == ipB.packed; | 28 return ipA.packed == ipB.packed; |
| 29 end | 29 end |
| 30 | |
| 31 local hex2bits = { | |
| 32 ["0"] = "0000", ["1"] = "0001", ["2"] = "0010", ["3"] = "0011", | |
| 33 ["4"] = "0100", ["5"] = "0101", ["6"] = "0110", ["7"] = "0111", | |
| 34 ["8"] = "1000", ["9"] = "1001", ["A"] = "1010", ["B"] = "1011", | |
| 35 ["C"] = "1100", ["D"] = "1101", ["E"] = "1110", ["F"] = "1111", | |
| 36 }; | |
| 37 | 30 |
| 38 local function new_ip(ipStr, proto) | 31 local function new_ip(ipStr, proto) |
| 39 local zone; | 32 local zone; |
| 40 if (not proto or proto == "IPv6") and ipStr:find('%', 1, true) then | 33 if (not proto or proto == "IPv6") and ipStr:find('%', 1, true) then |
| 41 ipStr, zone = ipStr:match("^(.-)%%(.*)"); | 34 ipStr, zone = ipStr:match("^(.-)%%(.*)"); |
| 64 | 57 |
| 65 function ip_methods:normal() | 58 function ip_methods:normal() |
| 66 return net.ntop(self.packed); | 59 return net.ntop(self.packed); |
| 67 end | 60 end |
| 68 | 61 |
| 69 function ip_methods.bits(ip) | 62 -- Returns the longest packed representation, i.e. IPv4 will be mapped |
| 70 return hex.encode(ip.packed):upper():gsub(".", hex2bits); | 63 function ip_methods.packed_full(ip) |
| 71 end | |
| 72 | |
| 73 function ip_methods.bits_full(ip) | |
| 74 if ip.proto == "IPv4" then | 64 if ip.proto == "IPv4" then |
| 75 ip = ip.toV4mapped; | 65 ip = ip.toV4mapped; |
| 76 end | 66 end |
| 77 return ip.bits; | 67 return ip.packed; |
| 78 end | 68 end |
| 79 | 69 |
| 80 local match; | 70 local match; |
| 81 | 71 |
| 82 local function commonPrefixLength(ipA, ipB) | 72 local function commonPrefixLength(ipA, ipB) |
| 83 ipA, ipB = ipA.bits_full, ipB.bits_full; | 73 return strbit.common_prefix_bits(ipA.packed_full, ipB.packed_full); |
| 84 for i = 1, 128 do | |
| 85 if ipA:sub(i,i) ~= ipB:sub(i,i) then | |
| 86 return i-1; | |
| 87 end | |
| 88 end | |
| 89 return 128; | |
| 90 end | 74 end |
| 91 | 75 |
| 92 -- Instantiate once | 76 -- Instantiate once |
| 93 local loopback = new_ip("::1"); | 77 local loopback = new_ip("::1"); |
| 94 local loopback4 = new_ip("127.0.0.0"); | 78 local loopback4 = new_ip("127.0.0.0"); |
| 236 elseif ipB.proto == "IPv4" then | 220 elseif ipB.proto == "IPv4" then |
| 237 ipB = ipB.toV4mapped; | 221 ipB = ipB.toV4mapped; |
| 238 bits = bits + (128 - 32); | 222 bits = bits + (128 - 32); |
| 239 end | 223 end |
| 240 end | 224 end |
| 241 return ipA.bits:sub(1, bits) == ipB.bits:sub(1, bits); | 225 return strbit.common_prefix_bits(ipA.packed, ipB.packed) >= bits; |
| 242 end | 226 end |
| 243 | 227 |
| 244 local function is_ip(obj) | 228 local function is_ip(obj) |
| 245 return getmetatable(obj) == ip_mt; | 229 return getmetatable(obj) == ip_mt; |
| 246 end | 230 end |
