Some metaserver logic.

This commit is contained in:
wan-may 2023-09-11 22:00:00 -03:00
parent a720ebf173
commit 7396f97433
4 changed files with 112 additions and 16 deletions

10
build.sh Normal file
View File

@ -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

View File

@ -1,20 +1,86 @@
local SERVERTIMEOUT = 30
local CLIENTTIMEOUT = 1
local shared = assert( require 'shared' )
local socket = assert( require 'socket' )
local packet = assert( shared.packet )
local udp = assert( socket.udp() )
--Servers broadcast their information here.
--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? )
local servers = {}
local clients = {}
local serverInfo = {}
local serverIPs = {}
local clientIPs = {}
local handlers = setmetatable({
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
print( "Starting Metaserver", socket.gettime() )
repeat
until socket.sleep( 2.0 - (socket.gettime() % 2.0) )
repeat
read( udp:receivefrom() )
prune( socket.gettime() )
io.flush()
until socket.sleep( 2.0 )

View File

@ -14,7 +14,7 @@ local svInfo = { version = 13,
local server = { tick = 0 }
local msIP, msPort
local msIP, msPort = "127.0.0.0", 8
local clients = {}
@ -35,7 +35,10 @@ function server.StartLocalClient()
end
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
--Incoming packet.
@ -61,10 +64,14 @@ function server.Start()
server.SetIP( socket.dns.toip(socket.dns.gethostname()), 51312 )
assert( udp:setsockname( tostring( svInfo.ip ), svInfo.port ))
server.StartLocalClient()
print( socket.gettime(), "Start." )
repeat
server.Parse( udp:receivefrom() )
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
function server.Advance()

View File

@ -8,9 +8,10 @@ local function newStruct( t )
assert( not( packet[ t.name ] or packet[ t.netname ] ))
packet[ t.name ] = t
packet[ t.netname ] = 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.size = ffi.sizeof( t.ct )
assert( t.size < 500, t.name )
setmetatable( t, mt )
--print( "Packet:", t.name, "Members:", #t + 1, "Size:", t.size, "Alignment:", ffi.alignof( t.ct ) )
@ -29,9 +30,15 @@ newStruct{
}
newStruct{
name = "requestServers",
name = "clientInfo",
netname = 22,
"char username[31]",
}
newStruct{
name = "metaServer",
netname = 123,
"char padding[999]"
"char padding[300]" --Just a bunch of padding to mitigate amplification.
}
newStruct{
@ -84,6 +91,12 @@ newStruct{
"char command",
}
newStruct{
name = "advertised",
netname = 144,
"uint32_t time",
}
local readBuffer = buffer.new( 1024 )
function packet.deserialise( str )
readBuffer:set( str )
@ -117,7 +130,7 @@ end
local writeBuffer = buffer.new( 1024 )
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 )
writeBuffer:putcdata( str, struct.size )
return writeBuffer
@ -129,7 +142,7 @@ end
mt.__call = packet.add
local testing = true
local testing = testing
--TESTS--
if testing then