From 2ca4a77b33c1e9f308391765d7d550ac701cca70 Mon Sep 17 00:00:00 2001 From: wan-may Date: Sun, 1 Oct 2023 20:16:10 -0300 Subject: [PATCH] Handle hash collision in handshake; properly prune old servers from browser. --- src/client/game.lua | 9 +++------ src/client/udp.lua | 25 +++++++++++++++---------- src/client/ui/browser.lua | 2 +- src/metaserver/main.lua | 2 ++ src/server/main.lua | 23 +++++++++++++++++------ src/shared/hash.lua | 2 +- src/shared/packet.lua | 5 +++++ 7 files changed, 44 insertions(+), 24 deletions(-) diff --git a/src/client/game.lua b/src/client/game.lua index 632ee2a..6b29c7a 100644 --- a/src/client/game.lua +++ b/src/client/game.lua @@ -58,8 +58,8 @@ function game.update( dt ) if t > 0.1 then t = 0 tick = tick + 1 - server.newPacket() - assert( server.send( packet.get() ) ) + server.newPacket( tick ) + assert( server.send() ) end end @@ -69,10 +69,7 @@ function game.newGame( ) end function game.disconnect( ) - server.newPacket() - server.disconnect() - server.send( packet.get() ) - return scene.mainmenu( server.disconnect() ) + return scene.mainmenu( server.disconnect( tick ) ) end function game.onLoad( params ) diff --git a/src/client/udp.lua b/src/client/udp.lua index 20417a6..51f153e 100644 --- a/src/client/udp.lua +++ b/src/client/udp.lua @@ -6,7 +6,6 @@ local udp = {} local packet = assert( require 'shared.packet' ) local hash = assert( require 'shared.hash' ) -local token local cxn = assert( socket.udp() ) local mscxn = assert( socket.udp() ) cxn:settimeout( 0 ) @@ -32,19 +31,20 @@ function udp.requestServerList() end function udp.newPacket( tick ) - packet.get() - if token then packet.connected{ token = token, tick = tick or 0 } end + if udp.token then packet.connected{ token = udp.token, tick = tick or 0 } end end function udp.setToken( token ) - token = token + print( "Setting server token:", token ) + udp.token = token end function udp.answerChallenge( svNonce ) local clNonce = hash.rand() packet.get() packet.clChimo{ nonce = clNonce, hash = hash.hash( clNonce, svNonce ) } - return cxn:send( packet.get() ) + print( "Received authentication nonce. Reply:", clNonce, svNonce ) + return udp.send() end function udp.isValid( ip, port ) @@ -57,17 +57,22 @@ end function udp.connect( ip, port ) assert( cxn:setpeername( ip, port ) ) print( "Connection request to:", ip, port ) - return udp.send( packet.get( packet.clientInfo{ username = config.plName } ) ) + return udp.send( packet.clientInfo{ username = config.plName }) end -function udp.disconnect( ) - udp.send( packet.get( packet.disconnect{ reason = 0 })) +function udp.disconnect( tick ) + for i = 1, 10 do + udp.newPacket( tick ) + packet.disconnect() + udp.send() + end + udp.setToken() cxn = assert( socket.udp() ) cxn:settimeout( 0 ) end -function udp.send( s ) - return cxn:send( s ) +function udp.send() + return cxn:send( packet.get() ) end return udp \ No newline at end of file diff --git a/src/client/ui/browser.lua b/src/client/ui/browser.lua index 23b1961..a2def5c 100644 --- a/src/client/ui/browser.lua +++ b/src/client/ui/browser.lua @@ -144,7 +144,7 @@ end local metaServerHandlers = setmetatable( { default = function() end, - heartbeat = serverList.clear, + connected = serverList.clear, serverInfo = serverList.add, }, {__index = function( t ) return t.default end }) diff --git a/src/metaserver/main.lua b/src/metaserver/main.lua index acc4c3f..4b5e46f 100644 --- a/src/metaserver/main.lua +++ b/src/metaserver/main.lua @@ -56,6 +56,8 @@ local handlers = setmetatable({ local t = socket.gettime() clients[ip].time = t + + packet.connected{ token = 5, tick = tick } for svIP, server in pairs( servers ) do print( "", svIP, packet.getString( server.info.svname )) diff --git a/src/server/main.lua b/src/server/main.lua index 783fc12..6197b77 100644 --- a/src/server/main.lua +++ b/src/server/main.lua @@ -9,6 +9,8 @@ assert( mscxn:setpeername( shared.metaserver.ip, shared.metaserver.port ), "Coul local udp local io = assert( io ) +local CLIENTTIMEOUT = 10 + local svInfo = packet.serverInfo{ version = 13, players = 0, capacity = 255, @@ -41,6 +43,7 @@ local handlers = setmetatable({ end client.tick = msg.tick + client.time = socket.gettime() server.currentClient = client end, @@ -58,11 +61,17 @@ local handlers = setmetatable({ --Client responds to handshake challenge. clChimo = function( clChimo, ip, port ) + + print( "Received handshake response." ) + + --No active challenge, don't send anything. local key = ip..":"..port if not connecting[ key ] then print( "Old connection attempt from:", key ) return true end + + --Compute session token. local remoteHash = clChimo.hash local clNonce = clChimo.nonce local svNonce = connecting[key].nonce @@ -72,10 +81,14 @@ local handlers = setmetatable({ return true end + --Hash collision. + while clients[token] do token = token + 1 end + --Successful handshake. - print( "Client connected:", ip, port, token ) + print( "Client connected:", token, port, ip ) clients[ token ] = connecting[ key ] - clients[ token ].token = token + clients[ token ].id = token + clients[ token ].time = socket.gettime() packet.connected{ token = token, tick = server.tick } return udp:sendto( packet.get(), ip, port ) end, @@ -126,11 +139,9 @@ end --Incoming packet. function server.Parse( msg, ip, port ) if (not msg) or (#msg < 1) then return end - print( "Parsing:", ip, port, #msg, msg ) local msgs, types = packet.deserialise( msg ) if msgs then for i = 1, #msgs do - print( "Received: ", types[i], ip, port ) if handlers[ types[i] ]( msgs[i], ip, port ) then break end end server.currentClient = false @@ -164,14 +175,14 @@ end function server.Advance() server.tick = server.tick + 1 + server.time = socket.gettime() if server.tick % 100 == 0 then for id, client in pairs( clients ) do packet.get() - print( "updating client:", id ) packet.connected{ token = id, tick = server.tick } udp:sendto( packet.get(), client.ip, client.port ) - if server.tick - client.tick > 1000 then + if server.time - client.time > CLIENTTIMEOUT then print( "dropping client:", id ) clients[id] = nil end diff --git a/src/shared/hash.lua b/src/shared/hash.lua index 9198c36..a827bc0 100644 --- a/src/shared/hash.lua +++ b/src/shared/hash.lua @@ -1,6 +1,6 @@ local math = math local bit = assert( require 'bit' ) -local max = math.huge +local max = 65536 math.randomseed( 4 ) --hash of a pair of 32-bit numbers return { diff --git a/src/shared/packet.lua b/src/shared/packet.lua index 8c707b0..2df5b1c 100644 --- a/src/shared/packet.lua +++ b/src/shared/packet.lua @@ -109,6 +109,11 @@ newStruct{ "char reason", } +newStruct{ + name = "debugLatency", + "uint32_t lastTick", +} + local readBuffer = buffer.new( 1024 ) function packet.deserialise( str ) readBuffer:set( str )