diff --git a/src/client.bat b/src/client.bat index 9870c06..7012773 100644 --- a/src/client.bat +++ b/src/client.bat @@ -1,2 +1,3 @@ +color 0a D:/dev/love/love.exe "./client/" pause \ No newline at end of file diff --git a/src/client/connecting.lua b/src/client/connecting.lua index cb8a3c8..e655c71 100644 --- a/src/client/connecting.lua +++ b/src/client/connecting.lua @@ -36,10 +36,28 @@ function connecting.draw() return false 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) if code == "escape" then return scene.browser() 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) time = time + dt @@ -49,12 +67,14 @@ function connecting.update(dt) server.connect( ip, port ) --return scene.loadScene( scene.game ) end - return false + + return connecting.read( server.receive() ) end function connecting:onLoad( params ) lg.setCanvas() time = 0 + attempts = 1 params = params or { ip = "8.8.8.8", port = 8 } ip, port = params.ip, params.port return server.isValid( ip, port ) and server.connect( ip, port ) diff --git a/src/client/udp.lua b/src/client/udp.lua index c0df8f8..c5e7eba 100644 --- a/src/client/udp.lua +++ b/src/client/udp.lua @@ -4,7 +4,9 @@ local config = assert( require 'config' ) 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 ) @@ -15,6 +17,8 @@ function udp.receive() return cxn:receive() end +udp.deserialise = packet.deserialise + function udp.receiveMeta() return mscxn:receive() end @@ -27,6 +31,17 @@ function udp.requestServerList() return mscxn:send( packet.get() ) 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 ) local s, e = socket.udp() if s then s, e = s:setpeername( ip, port ) end @@ -40,7 +55,9 @@ function udp.connect( ip, port ) end function udp.disconnect( ) - + udp.send( packet.get( packet.disconnect{ reason = 0 })) + cxn = assert( socket.udp() ) + cxn:settimeout( 0 ) end function udp.send( s ) diff --git a/src/server.bat b/src/server.bat index 3303c48..3805d0b 100644 --- a/src/server.bat +++ b/src/server.bat @@ -1,2 +1,3 @@ +color 04 D:/dev/love/love.exe "./server/" pause \ No newline at end of file diff --git a/src/server/main.lua b/src/server/main.lua index 8807391..6c77061 100644 --- a/src/server/main.lua +++ b/src/server/main.lua @@ -20,44 +20,52 @@ local svInfo = packet.serverInfo{ version = 13, local clients = {} local connecting = {} +local server = { tick = 0, } -local server = { - 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, +local handlers = setmetatable({ - advertised = function( ack, ip, port ) - print( "Advertised via:", 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 ) + 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() print( "Advertise." ) @@ -85,8 +93,8 @@ function server.Parse( msg, ip, port ) local msgs, types = packet.deserialise( msg ) if msgs then for i = 1, #msgs do - print( "Received: ", types[i], ip, port ); - ( server[ types[i] ] or print )( msgs[i], ip, port ) + print( "Received: ", types[i], ip, port ) + handlers[ types[i] ]( msgs[i], ip, port ) end end return server.Parse( udp:receivefrom() ) -- Process other packets. end @@ -94,13 +102,16 @@ end function server.SetIP( ipString, port ) svInfo.ip = shared.ip.fromString( ipString ) 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. elseif port < 65536 then - print( "Trying port:", port ) + print( "Could not use port:", ipString, port, err ) return server.SetIP( ipString, port + 1 ) else - print( "Could not use IP: "..ipString ) + print( "Could not use IP:", ipString, err ) return error( "Connection failed." ) end end @@ -109,8 +120,6 @@ end function server.Start() udp = assert( socket.udp() ) udp:settimeout(0) - server.SetIP( socket.dns.toip(socket.dns.gethostname()), 51312 ) - print( "Server started:", udp:getsockname() ) end function server.Advance() @@ -135,6 +144,7 @@ function love.update( dt ) server.Advance() if server.tick % 250 == 0 then server.Advertise() + server.Parse( mscxn:receive(), shared.metaserver.ip, shared.metaserver.port ) end end diff --git a/src/shared/hash.lua b/src/shared/hash.lua index 2acc8e0..88c55be 100644 --- a/src/shared/hash.lua +++ b/src/shared/hash.lua @@ -1,3 +1,11 @@ +local math = math local bit = assert( require 'bit' ) +local max = bit.tobit( 0xffffffff ) +math.randomseed( 4 ) --hash of a pair of 32-bit numbers -return { hash = bit.bxor, rand = function() return 5 end, hex = bit.tohex } \ No newline at end of file +return { + hash = bit.bxor, + hex = bit.tohex, + rand = function() + return math.random( 1, max ) + end, } \ No newline at end of file diff --git a/src/shared/packet.lua b/src/shared/packet.lua index 3f6f679..e78d9bb 100644 --- a/src/shared/packet.lua +++ b/src/shared/packet.lua @@ -102,8 +102,15 @@ newStruct{ } newStruct{ - name = "advertised", - "uint32_t time", + name = "advertised", + "uint32_t time", + "ipAddress ip", + "uint16_t port", +} + +newStruct{ + name = "disconnect", + "uint32_t reason", } local readBuffer = buffer.new( 1024 )