Anonymous user
Module:IP: Difference between revisions
From the Croc Wiki, the Croc encyclopedia
Jump to navigationJump to search
save progress on new implentation plan - an internal RawIP object used for bit operations on IP parts
(allow creation of IPAddress objects from their parts with newIPFromParts) |
(save progress on new implentation plan - an internal RawIP object used for bit operations on IP parts) |
||
Line 11:
local V6 = 'IPv6'
--------------------------------------------------------------------------------
-- Collection class
-- A table to hold items. Used internally.
--------------------------------------------------------------------------------
local
do
add = function (self, item)
self.n = self.n + 1
Line 26 ⟶ 25:
join = function (self, sep)
return table.concat(self, sep)
end,
}
Collection = function ()
return setmetatable({n = 0}, mt)
end
end
--------------------------------------------------------------------------------
-- RawIP class
-- Numeric representation of an IPv4 or IPv6 address. Used internally.
-- A RawIP object is constructed by adding data to a Collection object and
-- then giving it a new metatable. This is to avoid the memory overhead of
-- copying the data to a new table.
--------------------------------------------------------------------------------
local RawIP = {}
RawIP.__index = RawIP
function RawIP.newFromIPv4(ipStr)
-- If ipStr is a valid IPv4 string, return a collection of its parts.
-- Otherwise, return nil.
-- This representation is for compatibility with IPv6 addresses.
local octets = Collection()
local s = ipStr:match('^%s*(.-)%s*$') .. '.'
for item in s:gmatch('(.-)%.') do
octets:add(item)
end
if octets.n == 4 then
for i, s in ipairs(octets) do
if s:match('^%d+$') then
local num = tonumber(s)
if 0 <= num and num <= 255 then
if num > 0 and s:match('^0') then
-- A redundant leading zero is for an IP in octal.
return false
end
octets[i] = num
else
return false
end
else
return false
end
end
local parts = Collection()
for i = 1, 3, 2 do
parts:add(octets[i] * 256 + octets[i+1])
end
return setmetatable(parts, RawIP)
end
return nil
end
function RawIP.newFromIPv6(ipStr)
-- If ipStr is a valid IPv6 string, return a collection of its parts.
-- Otherwise, return nil.
ipStr = ipStr:match('^%s*(.-)%s*$')
local _, n = ipStr:gsub(':', ':')
if n < 7 then
ipStr, n = ipStr:gsub('::', string.rep(':', 9 - n))
end
local parts = Collection()
for item in (ipStr .. ':'):gmatch('(.-):') do
parts:add(item)
end
if parts.n == 8 then
for i, s in ipairs(parts) do
if s == '' then
parts[i] = 0
else
local num = tonumber('0x' .. s)
if num and 0 <= num and num <= 65535 then
parts[i] = num
else
return false
end
end
end
return setmetatable(parts, RawIP)
end
return nil
end
-- Return a copy of IPv4 or IPv6 parts, incremented or decremented.
-- Will wraparound:
Line 40 ⟶ 115:
-- decrement 0.0.0.0 → 255.255.255.255
-- :: → ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
local result =
result.n = self.n
local carry = down and 0xffff or 1
for i =
local sum =
if sum >= 0x10000 then
carry = down and 0x10000 or 1
Line 52 ⟶ 128:
result[i] = sum
end
return setmetatable(result, RawIP)
end
-- Return a copy of IPv4 or IPv6 parts, masked to length.
local result =
for i = 1, self.n do
if length > 0 then
if length >= 16 then
result[i] =
length = length - 16
else
result[i] = bit32.band(
bit32.arshift(0xffff8000, length - 1))
length = 0
Line 72 ⟶ 149:
end
end
return setmetatable(result, RawIP)
end
-- Return a copy of IPv4 or IPv6 parts, with the least-significant bits
-- (host bits) set to 1.
-- The most-significant length bits identify the network.
local bits =
local width
if length <= 0 then
Line 88 ⟶ 165:
width = bits - length
end
local result =
for i = self.n, 1, -1 do
if width > 0 then
if width >= 16 then
Line 95 ⟶ 173:
width = width - 16
else
result[i] = bit32.replace(
width = 0
end
else
result[i] =
end
end
return setmetatable(result, rawIP)
end
-- Return
-- if the current object is IPv4.
local z1, z2 -- indices of run of zeros to be displayed as "::"
local zstart, zcount
for i = 1, 9 do
-- Find left-most occurrence of longest run of two or more zeros.
if i < 9 and
if zstart then
zcount = zcount + 1
Line 129 ⟶ 208:
end
end
local parts =
for i = 1, 8 do
if z1 and z1 <= i and i <= z2 then
Line 143 ⟶ 222:
end
else
parts:add(string.format('%x',
end
end
return
end
-- Return an IPv4 string representation of the object. Behavior is undefined
-- if the current object is IPv6.
local parts = Collection()
for i = 1, 2 do
local w = self[i]
parts:add(math.floor(w / 256))
parts:add(w % 256)
end
return parts:join('.')
end
function RawIP:__tostring()
-- Return a string equivalent to given IP address (IPv4 or IPv6).
if
return self:_makeIPv4String()
else
return self:_makeIPv6String()
end
end
Line 178 ⟶ 262:
do
local dataKey = {} -- A unique key to access objects' internal data.
-- Metamethods that don't need upvalues
|