Some metaserver logic.
This commit is contained in:
parent
a720ebf173
commit
7396f97433
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
SRC_DIR="src"
|
||||||
|
LOVE_DIR="../../love"
|
||||||
|
BUILD_DIR="build"
|
||||||
|
|
||||||
|
cp -r $SRC_DIR/ $BUILD_DIR/
|
||||||
|
cd $BUILD_DIR/
|
||||||
|
zip -9 -r vision.love
|
||||||
|
|
||||||
|
cat ../../love/love.exe vision.love > vision.exe
|
|
@ -1,20 +1,86 @@
|
||||||
|
local SERVERTIMEOUT = 30
|
||||||
|
local CLIENTTIMEOUT = 1
|
||||||
|
|
||||||
local shared = assert( require 'shared' )
|
local shared = assert( require 'shared' )
|
||||||
local socket = assert( require 'socket' )
|
local socket = assert( require 'socket' )
|
||||||
|
local packet = assert( shared.packet )
|
||||||
local udp = assert( socket.udp() )
|
local udp = assert( socket.udp() )
|
||||||
|
|
||||||
--Servers broadcast their information here.
|
--Servers broadcast their information here.
|
||||||
--The metaserver builds a list of available servers. ( available meaning, "broadcasted in last ten heartbeats" )
|
--The metaserver builds a list of available servers. ( available meaning, "broadcasted in last ten heartbeats" )
|
||||||
--Clients ask the metaserver for this list ( maybe with some filter? )
|
--Clients ask the metaserver for this list ( maybe with some filter? )
|
||||||
|
local servers = {}
|
||||||
|
local clients = {}
|
||||||
|
|
||||||
local serverInfo = {}
|
local handlers = setmetatable({
|
||||||
local serverIPs = {}
|
|
||||||
local clientIPs = {}
|
|
||||||
|
|
||||||
local function Parse( packet, ip, port )
|
serverInfo = function( svInfo, ip, port )
|
||||||
|
if ip ~= tostring( svInfo.ip ) then return print("Server IP mismatch:", ip, svInfo.ip) end
|
||||||
|
local t = socket.gettime()
|
||||||
|
if not servers[ip] then servers[ip] = { ip = ip, port = port, info = svInfo } end
|
||||||
|
servers[ip].time = t
|
||||||
|
packet.advertised{ time = t }
|
||||||
|
|
||||||
|
local p = packet.get()
|
||||||
|
for i = 1, 10 do udp:sendto( p, ip, port ) end
|
||||||
|
end,
|
||||||
|
|
||||||
|
default = function( s, ip, port )
|
||||||
|
print( ip, port, "Malformed message: ", s )
|
||||||
|
end,
|
||||||
|
|
||||||
|
metaServer = function()
|
||||||
|
|
||||||
|
end,
|
||||||
|
|
||||||
|
clientInfo = function( clientInfo, ip, port )
|
||||||
|
if ip ~= tostring( clientInfo.ip ) then
|
||||||
|
return print( ip, port, "Client IP mismatch:", clientInfo.ip )
|
||||||
|
end
|
||||||
|
|
||||||
|
if clients[ip] then print( ip, port, "Client request timeout." ) end
|
||||||
|
|
||||||
|
local t = socket.gettime()
|
||||||
|
clients[ip].time = t
|
||||||
|
|
||||||
|
for i, server in ipairs( servers ) do
|
||||||
|
packet.serverInfo( server.info )
|
||||||
|
end
|
||||||
|
|
||||||
|
local p = packet.get()
|
||||||
|
for i = 1, 10 do udp:sendto( p, ip, port ) end
|
||||||
|
end
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
__index = function(t) return t.default end
|
||||||
|
})
|
||||||
|
|
||||||
|
local function read(msg, ip, port)
|
||||||
|
if not msg then return end
|
||||||
|
local msgs, types = packet.deserialise( msg )
|
||||||
|
if types[1] ~= "metaServer" then
|
||||||
|
print( ip, port, "Dropped packet, no padding." )
|
||||||
|
return read( udp:receivefrom() )
|
||||||
|
end
|
||||||
|
for i = 1, #msgs do
|
||||||
|
handlers[ types[i] ]( msgs[i], ip, port )
|
||||||
|
end
|
||||||
|
return read( udp:receivefrom() )
|
||||||
|
end
|
||||||
|
|
||||||
|
local function prune( t )
|
||||||
|
print( "Pruning", socket.gettime() )
|
||||||
|
for ip, server in pairs(servers) do
|
||||||
|
if server.time < t - SERVERTIMEOUT then
|
||||||
|
servers[ip] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
print( "Starting Metaserver", socket.gettime() )
|
print( "Starting Metaserver", socket.gettime() )
|
||||||
repeat
|
repeat
|
||||||
|
read( udp:receivefrom() )
|
||||||
until socket.sleep( 2.0 - (socket.gettime() % 2.0) )
|
prune( socket.gettime() )
|
||||||
|
io.flush()
|
||||||
|
until socket.sleep( 2.0 )
|
|
@ -14,7 +14,7 @@ local svInfo = { version = 13,
|
||||||
|
|
||||||
local server = { tick = 0 }
|
local server = { tick = 0 }
|
||||||
|
|
||||||
local msIP, msPort
|
local msIP, msPort = "127.0.0.0", 8
|
||||||
|
|
||||||
local clients = {}
|
local clients = {}
|
||||||
|
|
||||||
|
@ -35,7 +35,10 @@ function server.StartLocalClient()
|
||||||
end
|
end
|
||||||
|
|
||||||
function server.Advertise()
|
function server.Advertise()
|
||||||
udp:sendto( packet.get( packet.serverInfo( svInfo ) ) , msIP, msPort )
|
print( socket.gettime(), "Advertise." )
|
||||||
|
packet.metaServer{ padding = "" }
|
||||||
|
packet.serverInfo( svInfo )
|
||||||
|
udp:sendto( packet.get() , msIP, msPort )
|
||||||
end
|
end
|
||||||
|
|
||||||
--Incoming packet.
|
--Incoming packet.
|
||||||
|
@ -61,10 +64,14 @@ function server.Start()
|
||||||
server.SetIP( socket.dns.toip(socket.dns.gethostname()), 51312 )
|
server.SetIP( socket.dns.toip(socket.dns.gethostname()), 51312 )
|
||||||
assert( udp:setsockname( tostring( svInfo.ip ), svInfo.port ))
|
assert( udp:setsockname( tostring( svInfo.ip ), svInfo.port ))
|
||||||
server.StartLocalClient()
|
server.StartLocalClient()
|
||||||
|
print( socket.gettime(), "Start." )
|
||||||
repeat
|
repeat
|
||||||
server.Parse( udp:receivefrom() )
|
server.Parse( udp:receivefrom() )
|
||||||
server.Advance()
|
server.Advance()
|
||||||
until socket.sleep( 0.1 - (socket.gettime() % 0.1) )
|
if server.tick % 20 == 0 then
|
||||||
|
server.Advertise()
|
||||||
|
end
|
||||||
|
until socket.sleep( 0.1 )
|
||||||
end
|
end
|
||||||
|
|
||||||
function server.Advance()
|
function server.Advance()
|
||||||
|
|
|
@ -11,6 +11,7 @@ local function newStruct( t )
|
||||||
ffi.cdef(("typedef struct {uint8_t netname;\n%s;\n} %s;"):format( table.concat( t, ";\n" ), t.name ))
|
ffi.cdef(("typedef struct {uint8_t netname;\n%s;\n} %s;"):format( table.concat( t, ";\n" ), t.name ))
|
||||||
t.ct = ffi.typeof( ffi.new( t.name ) )
|
t.ct = ffi.typeof( ffi.new( t.name ) )
|
||||||
t.size = ffi.sizeof( t.ct )
|
t.size = ffi.sizeof( t.ct )
|
||||||
|
assert( t.size < 500, t.name )
|
||||||
setmetatable( t, mt )
|
setmetatable( t, mt )
|
||||||
|
|
||||||
--print( "Packet:", t.name, "Members:", #t + 1, "Size:", t.size, "Alignment:", ffi.alignof( t.ct ) )
|
--print( "Packet:", t.name, "Members:", #t + 1, "Size:", t.size, "Alignment:", ffi.alignof( t.ct ) )
|
||||||
|
@ -29,9 +30,15 @@ newStruct{
|
||||||
}
|
}
|
||||||
|
|
||||||
newStruct{
|
newStruct{
|
||||||
name = "requestServers",
|
name = "clientInfo",
|
||||||
|
netname = 22,
|
||||||
|
"char username[31]",
|
||||||
|
}
|
||||||
|
|
||||||
|
newStruct{
|
||||||
|
name = "metaServer",
|
||||||
netname = 123,
|
netname = 123,
|
||||||
"char padding[999]"
|
"char padding[300]" --Just a bunch of padding to mitigate amplification.
|
||||||
}
|
}
|
||||||
|
|
||||||
newStruct{
|
newStruct{
|
||||||
|
@ -84,6 +91,12 @@ newStruct{
|
||||||
"char command",
|
"char command",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newStruct{
|
||||||
|
name = "advertised",
|
||||||
|
netname = 144,
|
||||||
|
"uint32_t time",
|
||||||
|
}
|
||||||
|
|
||||||
local readBuffer = buffer.new( 1024 )
|
local readBuffer = buffer.new( 1024 )
|
||||||
function packet.deserialise( str )
|
function packet.deserialise( str )
|
||||||
readBuffer:set( str )
|
readBuffer:set( str )
|
||||||
|
@ -117,7 +130,7 @@ end
|
||||||
|
|
||||||
local writeBuffer = buffer.new( 1024 )
|
local writeBuffer = buffer.new( 1024 )
|
||||||
function packet.add( struct, data )
|
function packet.add( struct, data )
|
||||||
local str = ffi.new( struct.ct, data )
|
local str = ffi.new( struct.ct, data or 0 )
|
||||||
str.netname = assert( struct.netname )
|
str.netname = assert( struct.netname )
|
||||||
writeBuffer:putcdata( str, struct.size )
|
writeBuffer:putcdata( str, struct.size )
|
||||||
return writeBuffer
|
return writeBuffer
|
||||||
|
@ -129,7 +142,7 @@ end
|
||||||
|
|
||||||
mt.__call = packet.add
|
mt.__call = packet.add
|
||||||
|
|
||||||
local testing = true
|
local testing = testing
|
||||||
--TESTS--
|
--TESTS--
|
||||||
if testing then
|
if testing then
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue