From 2f53f7d8ee25acb45b45c31f58777b100112378d Mon Sep 17 00:00:00 2001 From: Lizzy Fleckenstein Date: Mon, 8 Jun 2026 20:00:53 +0200 Subject: consider local addresses as candidates for connecting to server --- client.lua | 39 ++++++++++++++++++++++++++++++--------- common.lua | 4 ++++ main.lua | 1 + matchsrv.lua | 39 +++++++++++++++++++++++++-------------- server.lua | 18 ++++++++++++++++-- util.lua | 6 ++++++ 6 files changed, 82 insertions(+), 25 deletions(-) diff --git a/client.lua b/client.lua index 30f886d..61fe8c2 100644 --- a/client.lua +++ b/client.lua @@ -12,12 +12,22 @@ local function create_client(secret) return clt end -local function connect(clt, addr) - clt.server = clt.host:connect(addr) +local function connect(clt, addrs) + clt.server_candidates = {} + for _, addr in ipairs(addrs) do + clt.server_candidates[clt.host:connect(addr)] = true + end clt.server_req = socket.gettime() clt.status = "wait_server" end +local function remove_candidates(clt) + for s in pairs(clt.server_candidates) do + s:disconnect() + end + clt.server_candidates = nil +end + function client.join(invite, match_addr) local invite_dec = util.base64_dec(invite) if not invite_dec then @@ -38,17 +48,24 @@ end function client.connect(addr, secret) local clt = create_client(secret) - connect(clt, addr) + connect(clt, { addr }) return clt end local function handle_match(clt, pkt) if pkt.type == "client_join" then - if type(pkt.peer_addr) ~= "string" then - print("[client] client_join: invalid peer_addr") + if type(pkt.candidates) ~= "table" then + print("[client] client_join: invalid candidates") return end - connect(clt, pkt.peer_addr) + for _, c in ipairs(pkt.candidates) do + if type(c) ~= "string" then + print("[client] client_join: invalid candidates") + return + end + end + + connect(clt, pkt.candidates) elseif pkt.type == "client_join_fail" then clt.status = "fail_match" end @@ -83,17 +100,20 @@ function client.update(clt) end end elseif event.type == "connect" then - if event.peer == clt.match and clt.status == "wait_match" then + if clt.status == "wait_match" and event.peer == clt.match then util.send(clt.match, { type = "match_join", game_id = util.base64_enc(clt.game_id) }) - elseif event.peer == clt.server and clt.status == "wait_server" then + elseif clt.status == "wait_server" and clt.server_candidates[event.peer] then + clt.server = event.peer + clt.server_candidates[clt.server] = nil util.send(clt.server, { type = "server_hi", secret = util.base64_enc(clt.secret) }) + remove_candidates(clt) else event.peer:disconnect_now() end print("[client] connect " .. tostring(event.peer)) elseif event.type == "disconnect" then print("[client] disconnect " .. tostring(event.peer)) - if event.peer == clt.server and clt.status == "active" then + if event.peer == clt.server then clt.status = "disco" end end @@ -122,6 +142,7 @@ end function client.close(clt) if clt.match then clt.match:disconnect() end if clt.server then clt.server:disconnect() end + if clt.server_candidates then remove_candidates(clt) end clt.host:flush() clt.host:destroy() end diff --git a/common.lua b/common.lua index 6a04d0f..98268ab 100644 --- a/common.lua +++ b/common.lua @@ -1,5 +1,9 @@ return { default_match_addr = "ivy.vlhl.dev:18252", + -- any public IP address (in this case: ivy.vlhl.dev) + -- this address is not pinged or connected to + -- used to look up our own local ip address + route_lookup_target = "94.16.117.28", gameid_len = 8, secret_len = 4, } diff --git a/main.lua b/main.lua index 30f21a5..a5dd579 100644 --- a/main.lua +++ b/main.lua @@ -73,6 +73,7 @@ local function start_server(save) else srv = s end + show(dialog.loading, "Registering game...") end local function create_save(save) diff --git a/matchsrv.lua b/matchsrv.lua index 315573c..a8ae92e 100755 --- a/matchsrv.lua +++ b/matchsrv.lua @@ -5,33 +5,44 @@ local common = require("common") local host = enet.host_create("0.0.0.0:18252") -local game_to_peer = {} -local peer_to_game = {} +local games_by_id = {} +local games_by_peer = {} local function remove_game(peer) - local game = peer_to_game[peer] + local game = games_by_peer[peer] if game then - game_to_peer[game] = nil - peer_to_game[peer] = nil + games_by_id[game.id] = nil + games_by_peer[game.peer] = nil end end local function handle(peer, pkt) if pkt.type == "match_register" then + if pkt.candidates ~= nil and type(pkt.candidates) ~= "table" then + return + end + + local game = { + peer = peer, + id = util.rand_string(common.gameid_len), + candidates = pkt.candidates or {}, + } + table.insert(game.candidates, tostring(peer)) + remove_game(peer) - local game_id = util.rand_string(common.gameid_len) - peer_to_game[peer] = game_id - game_to_peer[game_id] = peer - util.send(peer, { type = "server_match", game_id = util.base64_enc(game_id) }) + games_by_peer[game.peer] = game + games_by_id[game.id] = game + + util.send(peer, { type = "server_match", game_id = util.base64_enc(game.id) }) print(peer, "registered game") elseif pkt.type == "match_join" then local game_id = type(pkt.game_id) == "string" and util.base64_dec(pkt.game_id) if game_id then - local server = game_id and game_to_peer[game_id] - if server then - util.send(server, { type = "server_join", peer_addr = tostring(peer) }) - util.send(peer, { type = "client_join", peer_addr = tostring(server) }) - print(peer, "joined game", server) + local game = games_by_id[game_id] + if game then + util.send(game.peer, { type = "server_join", peer_addr = tostring(peer) }) + util.send(peer, { type = "client_join", peer_addr = tostring(game.peer), candidates = game.candidates }) + print(peer, "joined game", game.peer) else util.send(peer, { type = "client_join_fail" }) print(peer, "failed to join game") diff --git a/server.lua b/server.lua index 8d85dcd..a51564c 100644 --- a/server.lua +++ b/server.lua @@ -3,9 +3,18 @@ local socket = require("socket") local util = require("util") local common = require("common") local save_file = require("save_file") +local socket = require("socket") local server = {} +local function get_local_ip() + local sock = socket.udp() + sock:setpeername(common.route_lookup_target, 1024) + local ip = sock:getsockname() + sock:close() + return ip +end + local function migrate_save(save) save.players = save.players or {} end @@ -108,7 +117,11 @@ function server.create(filename, match_addr) end function server.port(srv) - return srv.host:get_socket_address():match(":([^:]*)$") + return util.split_addr(srv.host:get_socket_address()).port +end + +function server.local_addr(srv) + return get_local_ip() .. ":" .. server.port(srv) end local function handle_match(srv, pkt) @@ -214,7 +227,8 @@ function server.update(srv, wait) end elseif event.type == "connect" then if event.peer == srv.match then - util.send(srv.match, { type = "match_register" }) + util.send(srv.match, { type = "match_register", + candidates = { server.local_addr(srv) } }) end print("[server] connect " .. tostring(event.peer)) elseif event.type == "disconnect" then diff --git a/util.lua b/util.lua index dda250e..8eab1db 100644 --- a/util.lua +++ b/util.lua @@ -39,6 +39,11 @@ else end end +local function split_addr(addr) + local host, port = addr:match("(.*):([^:]*)$") + return { host = host, port = port } +end + return { rand_string = rand_string, mkdir = mkdir, @@ -47,4 +52,5 @@ return { json_dec = json_dec, json_enc = json_enc, send = send, + split_addr = split_addr, } -- cgit v1.2.3