Connection protocol. Joinable servers!

This commit is contained in:
wan-may 2023-09-23 19:08:08 -03:00
parent 76beae271c
commit 74e328d86c
7 changed files with 111 additions and 47 deletions

View File

@ -1,2 +1,3 @@
color 0a
D:/dev/love/love.exe "./client/" D:/dev/love/love.exe "./client/"
pause pause

View File

@ -36,10 +36,28 @@ function connecting.draw()
return false return false
end end
function connecting.svChimo( msg )
return server.answerChallenge( msg.nonce )
end
function connecting.connected( msg )
server.setToken( msg.token )
return scene.game()
end
function connecting.keypressed(key, code, isrepeat) function connecting.keypressed(key, code, isrepeat)
if code == "escape" then return scene.browser() end if code == "escape" then return scene.browser() end
end end
function connecting.read( msg )
if not msg then return false end
local msgs, types = server.deserialise( msg )
for i = 1, #msgs do
( connecting[ types[i] ] or print )( msgs[i], ip, port )
end
return connecting.read( server.receive() )
end
function connecting.update(dt) function connecting.update(dt)
time = time + dt time = time + dt
@ -49,12 +67,14 @@ function connecting.update(dt)
server.connect( ip, port ) server.connect( ip, port )
--return scene.loadScene( scene.game ) --return scene.loadScene( scene.game )
end end
return false
return connecting.read( server.receive() )
end end
function connecting:onLoad( params ) function connecting:onLoad( params )
lg.setCanvas() lg.setCanvas()
time = 0 time = 0
attempts = 1
params = params or { ip = "8.8.8.8", port = 8 } params = params or { ip = "8.8.8.8", port = 8 }
ip, port = params.ip, params.port ip, port = params.ip, params.port
return server.isValid( ip, port ) and server.connect( ip, port ) return server.isValid( ip, port ) and server.connect( ip, port )

View File

@ -4,7 +4,9 @@ local config = assert( require 'config' )
local udp = {} local udp = {}
local packet = assert( require 'shared.packet' ) local packet = assert( require 'shared.packet' )
local hash = assert( require 'shared.hash' )
local token
local cxn = assert( socket.udp() ) local cxn = assert( socket.udp() )
local mscxn = assert( socket.udp() ) local mscxn = assert( socket.udp() )
cxn:settimeout( 0 ) cxn:settimeout( 0 )
@ -15,6 +17,8 @@ function udp.receive()
return cxn:receive() return cxn:receive()
end end
udp.deserialise = packet.deserialise
function udp.receiveMeta() function udp.receiveMeta()
return mscxn:receive() return mscxn:receive()
end end
@ -27,6 +31,17 @@ function udp.requestServerList()
return mscxn:send( packet.get() ) return mscxn:send( packet.get() )
end end
function udp.setToken( token )
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() )
end
function udp.isValid( ip, port ) function udp.isValid( ip, port )
local s, e = socket.udp() local s, e = socket.udp()
if s then s, e = s:setpeername( ip, port ) end if s then s, e = s:setpeername( ip, port ) end
@ -40,7 +55,9 @@ function udp.connect( ip, port )
end end
function udp.disconnect( ) function udp.disconnect( )
udp.send( packet.get( packet.disconnect{ reason = 0 }))
cxn = assert( socket.udp() )
cxn:settimeout( 0 )
end end
function udp.send( s ) function udp.send( s )

View File

@ -1,2 +1,3 @@
color 04
D:/dev/love/love.exe "./server/" D:/dev/love/love.exe "./server/"
pause pause

View File

@ -20,44 +20,52 @@ local svInfo = packet.serverInfo{ version = 13,
local clients = {} local clients = {}
local connecting = {} local connecting = {}
local server = { tick = 0, }
local server = { local handlers = setmetatable({
tick = 0,
clientInfo = function( clientInfo, ip, port )
local key = ip..port
connecting[key] = connecting[key] or {}
local client = connecting[key]
local nonce = shared.hash.rand()
client.nonce = nonce
print( "Received connection request from:", ip, port )
print( "Sending authentication nonce:", nonce )
packet.svChimo{ nonce = nonce }
return udp:sendto( packet.get(), ip, port )
end,
clChimo = function( clChimo, ip, port )
if not connecting[ ip..port ] then
return print( "Old connection attempt from:", ip, port )
end
local remoteHash = clChimo.hash
local clNonce = clChimo.nonce
local svNonce = connecting[ip..port].nonce
local localHash = shared.hash.hash( clNonce, svNonce )
if localHash ~= remoteHash then
return print( "Hashes differ:", shared.hash.hex( clNonce ), shared.hash.hex( svNonce ) )
end
print( "Client connected:", ip, port, localHash )
clients[ localHash ] = { ip = ip, port = port }
packet.connected{ token = localHash }
return udp:sendto( packet.get(), ip, port )
end,
advertised = function( ack, ip, port ) clChimo = function( clChimo, ip, port )
print( "Advertised via:", ip, port ) if not connecting[ ip..port ] then
end, return print( "Old connection attempt from:", ip, port )
} end
local remoteHash = clChimo.hash
local clNonce = clChimo.nonce
local svNonce = connecting[ip..port].nonce
local localHash = shared.hash.hash( clNonce, svNonce )
if localHash ~= remoteHash then
return print( "Hashes differ:", shared.hash.hex( clNonce ), shared.hash.hex( svNonce ) )
end
print( "Client connected:", ip, port, localHash )
clients[ localHash ] = { ip = ip, port = port }
packet.connected{ token = localHash }
return udp:sendto( packet.get(), ip, port )
end,
advertised = function( ack, ip, port )
if ip ~= shared.metaserver.ip then return print( "Advertisement acked from rogue address:", ip, port ) end
if udp:getsockname() then
assert( udp:getsockname() == tostring( ack.ip ) )
return print( "Advertised. Address already set." )
end
print( "Advertised. Setting address:", ack.ip, ack.port )
server.SetIP( tostring( ack.ip ), ack.port )
end,
clientInfo = function( clientInfo, ip, port )
local key = ip..port
connecting[key] = connecting[key] or {}
local client = connecting[key]
local nonce = shared.hash.rand()
client.nonce = nonce
print( "Received connection request from:", ip, port )
print( "Sending authentication nonce:", nonce )
packet.svChimo{ nonce = nonce }
return udp:sendto( packet.get(), ip, port )
end,
}, {__index = function() return print end })
function server.Advertise() function server.Advertise()
print( "Advertise." ) print( "Advertise." )
@ -85,8 +93,8 @@ function server.Parse( msg, ip, port )
local msgs, types = packet.deserialise( msg ) local msgs, types = packet.deserialise( msg )
if msgs then for i = 1, #msgs do if msgs then for i = 1, #msgs do
print( "Received: ", types[i], ip, port ); print( "Received: ", types[i], ip, port )
( server[ types[i] ] or print )( msgs[i], ip, port ) handlers[ types[i] ]( msgs[i], ip, port )
end end end end
return server.Parse( udp:receivefrom() ) -- Process other packets. return server.Parse( udp:receivefrom() ) -- Process other packets.
end end
@ -94,13 +102,16 @@ end
function server.SetIP( ipString, port ) function server.SetIP( ipString, port )
svInfo.ip = shared.ip.fromString( ipString ) svInfo.ip = shared.ip.fromString( ipString )
svInfo.port = port svInfo.port = port
if udp:setsockname( ipString, port ) then local ok, err = udp:setsockname( ipString, port )
if ok then
print( "Server IP:", udp:getsockname() )
return true
--Find another port. --Find another port.
elseif port < 65536 then elseif port < 65536 then
print( "Trying port:", port ) print( "Could not use port:", ipString, port, err )
return server.SetIP( ipString, port + 1 ) return server.SetIP( ipString, port + 1 )
else else
print( "Could not use IP: "..ipString ) print( "Could not use IP:", ipString, err )
return error( "Connection failed." ) return error( "Connection failed." )
end end
end end
@ -109,8 +120,6 @@ end
function server.Start() function server.Start()
udp = assert( socket.udp() ) udp = assert( socket.udp() )
udp:settimeout(0) udp:settimeout(0)
server.SetIP( socket.dns.toip(socket.dns.gethostname()), 51312 )
print( "Server started:", udp:getsockname() )
end end
function server.Advance() function server.Advance()
@ -135,6 +144,7 @@ function love.update( dt )
server.Advance() server.Advance()
if server.tick % 250 == 0 then if server.tick % 250 == 0 then
server.Advertise() server.Advertise()
server.Parse( mscxn:receive(), shared.metaserver.ip, shared.metaserver.port )
end end
end end

View File

@ -1,3 +1,11 @@
local math = math
local bit = assert( require 'bit' ) local bit = assert( require 'bit' )
local max = bit.tobit( 0xffffffff )
math.randomseed( 4 )
--hash of a pair of 32-bit numbers --hash of a pair of 32-bit numbers
return { hash = bit.bxor, rand = function() return 5 end, hex = bit.tohex } return {
hash = bit.bxor,
hex = bit.tohex,
rand = function()
return math.random( 1, max )
end, }

View File

@ -102,8 +102,15 @@ newStruct{
} }
newStruct{ newStruct{
name = "advertised", name = "advertised",
"uint32_t time", "uint32_t time",
"ipAddress ip",
"uint16_t port",
}
newStruct{
name = "disconnect",
"uint32_t reason",
} }
local readBuffer = buffer.new( 1024 ) local readBuffer = buffer.new( 1024 )