Skip to content
Open
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 46 additions & 15 deletions mmdb/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,23 @@ local geodb_mt = {
local data_types = {}
local getters = {}

local function open_db(filename)
local fd = assert(io.open(filename, "rb"))
local function fail(safe, ...)
if safe then return nil, ... end
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return on own line

error(..., 2)
end

local function open_db(safe, filename)
local fd, err = io.open(filename, "rb")
if not fd then
return fail(safe, err)
end

local contents, err = fd:read("*a")
fd:close()
assert(contents, err)

if not contents then
return fail(safe, err)
end

local start_metadata do
-- Find data section seperator; at most it's 128kb from the end
Expand All @@ -29,11 +41,12 @@ local function open_db(filename)
start_metadata = e + 1
end
if start_metadata == nil then
error("Invalid MaxMind Database")
return fail(safe, "Invalid MaxMind Database")
end
end

local self = setmetatable({
safe = not not safe;
contents = contents;
start_metadata = start_metadata;
data = nil;
Expand All @@ -47,7 +60,7 @@ local function open_db(filename)

local getter = getters[data.record_size]
if getter == nil then
error("Unsupported record size: " .. data.record_size)
return fail(self.safe, "Unsupported record size: " .. tostring(data.record_size))
end
self.left, self.right, self.record_length = getter.left, getter.right, getter.record_length

Expand Down Expand Up @@ -320,10 +333,10 @@ getters[32] = {
function geodb_methods:search(bits, node)
node = node or 0
local seen = { [node] = true }
for _, direction in ipairs(bits) do
for i = 1, #bits do
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why change this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In theory it more faster way to do iteration. So I just prefer this one.
I saw this in several places. e.g https://springrts.com/wiki/Lua_Performance#TEST_9:_for-loops.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, but there is a slight change in behaviour: ipairs always stops at first nil; while your code is undefined in the presence of nils.

I'm happy to make the change, but please include it in a different commit (should possibly even be in a different PR, but I suppose we can sneak it in)

local offset = node * self.record_length + 1
local record_value
if direction then
if bits[i] then
record_value = self:right(offset)
else
record_value = self:left(offset)
Expand Down Expand Up @@ -368,12 +381,17 @@ end

local function ipv4_to_bit_array(str)
local o1, o2, o3, o4 = str:match("(%d%d?%d?)%.(%d%d?%d?)%.(%d%d?%d?)%.(%d%d?%d?)")
assert(o1, "invalid IPv4 address")
if not o1 then
return nil, "invalid IPv4 address"
end
o1 = tonumber(o1, 10)
o2 = tonumber(o2, 10)
o3 = tonumber(o3, 10)
o4 = tonumber(o4, 10)
assert(o1 <= 255 and o2 <= 255 and o3 <= 255 and o4 <= 255, "invalid IPv4 address")
if not (o1 <= 255 and o2 <= 255 and o3 <= 255 and o4 <= 255) then
return nil, "invalid IPv4 address"
end

return {
math.floor(o1 / 128) % 2 == 1;
math.floor(o1 / 64) % 2 == 1;
Expand Down Expand Up @@ -411,7 +429,11 @@ local function ipv4_to_bit_array(str)
end

function geodb_methods:search_ipv4(str)
return select(2, self:search(ipv4_to_bit_array(str), self.ipv4_start))
local bits, err = ipv4_to_bit_array(str)
if not bits then
return fail(self.safe, err)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to call fail here: can return bits, err to the caller.

end
return select(2, self:search(bits, self.ipv4_start))
end

local function ipv6_split(str)
Expand All @@ -420,7 +442,7 @@ local function ipv6_split(str)
for u16 in str:gmatch("(%x%x?%x?%x?):?") do
n = n + 1
u16 = tonumber(u16, 16)
assert(u16, "invalid IPv6 address")
if not u16 then return nil, "invalid IPv6 address" end
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please put return on it's own line

components[n] = u16
end
return components, n
Expand All @@ -429,17 +451,21 @@ end
local function ipv6_to_bit_array(str)
local a, b = str:match("^([%x:]-)::([%x:]*)$")
local components, n = ipv6_split(a or str)
if not components then return nil, n end
if a ~= nil then
local end_components, m = ipv6_split(b)
assert(m+n <= 7, "invalid IPv6 address")
if not end_components then return nil, m end
if m+n > 7 then return nil, "invalid IPv6 address" end
for i = n+1, 8-m do
components[i] = 0
end
for i = 8-m+1, 8 do
components[i] = end_components[i-8+m]
end
else
assert(n == 8, "invalid IPv6 address")
if n ~= 8 then
return nil, "invalid IPv6 address"
end
end
-- Now components is an array of 16bit components
local bits = {}
Expand All @@ -453,9 +479,14 @@ local function ipv6_to_bit_array(str)
end

function geodb_methods:search_ipv6(str)
return select(2, self:search(ipv6_to_bit_array(str)))
local bits, err = ipv6_to_bit_array(str)
if not bits then
return fail(self.safe, err)
end
return select(2, self:search(bits))
end

return {
open = open_db;
open = function(...) return open_db(false, ...) end;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please just declare these in the body of the file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May be use this one ?

local mmdb = { here you can add e.g. version info, module name }

function mmdb.open() ...end

function mmdb.open_safe() ...end

return mmdb

open_safe = function(...) return open_db(true, ...) end;
}