From 509a129141e7ba6b73213d1c15cf2d0b83508ce6 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Alexis=20Laferri=C3=A8re?= Date: Sat, 27 May 2017 22:03:21 -0400 Subject: [PATCH] gamnit: move up UDP discovery logic from Tinks! to the lib MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Alexis Laferrière --- contrib/tinks/src/client/base.nit | 20 +++---------- contrib/tinks/src/common.nit | 3 +- contrib/tinks/src/server/server.nit | 27 ++---------------- lib/gamnit/network/client.nit | 54 ++++++++++++++++++++++++++++++++++- lib/gamnit/network/common.nit | 11 +++++++ lib/gamnit/network/server.nit | 49 ++++++++++++++++++++++++++++--- 6 files changed, 116 insertions(+), 48 deletions(-) diff --git a/contrib/tinks/src/client/base.nit b/contrib/tinks/src/client/base.nit index bca5ae3..b3ebd09 100644 --- a/contrib/tinks/src/client/base.nit +++ b/contrib/tinks/src/client/base.nit @@ -35,22 +35,10 @@ redef class App else print "Looking for a server..." - var s = new UDPSocket - s.enable_broadcast = true - s.blocking = false - s.broadcast(discovery_port, "Server? {handshake_app_name}") - nanosleep(0, 100_000_000) - - var ptr = new Ref[nullable SocketAddress](null) - var resp = s.recv_from(1024, ptr) - var src = ptr.item - - if not resp.is_empty then - var words = resp.split(" ") - if words.length == 3 and words[0] == "Server!" and words[1] == handshake_app_name and words[2].is_numeric then - address = src.address - port = words[2].to_i - end + var servers = discover_local_servers + if servers.not_empty then + address = servers.first.address + port = servers.first.port end end diff --git a/contrib/tinks/src/common.nit b/contrib/tinks/src/common.nit index b215d09..e7a82c9 100644 --- a/contrib/tinks/src/common.nit +++ b/contrib/tinks/src/common.nit @@ -26,6 +26,5 @@ redef class Sys # Default listening port of the server fun default_listening_port: Int do return 18721 - # Port to which clients send discovery requests - fun discovery_port: Int do return 18722 + redef fun discovery_port do return 18722 end diff --git a/contrib/tinks/src/server/server.nit b/contrib/tinks/src/server/server.nit index 58555ae..6c63670 100644 --- a/contrib/tinks/src/server/server.nit +++ b/contrib/tinks/src/server/server.nit @@ -26,13 +26,6 @@ redef class RemoteClient end redef class Server - # `UDPSocket` to which clients send discovery requests - var discovery_socket: UDPSocket do - var s = new UDPSocket - s.blocking = false - s.bind(null, discovery_port) - return s - end # The current game var game = new TGame is lazy, writable @@ -62,24 +55,8 @@ redef class Server # Do game logic var turn = game.do_turn - # Respond to discovery requests - loop - var ptr = new Ref[nullable SocketAddress](null) - var read = discovery_socket.recv_from(1024, ptr) - - # No sender means there is no request (an error would also do it) - var sender = ptr.item - if sender == null then break - - var words = read.split(" ") - if words.length != 2 or words[0] != "Server?" or words[1] != handshake_app_name then - print "Server Warning: Rejected discovery request '{read}'" - continue - end - - discovery_socket.send_to(sender.address, sender.port, - "Server! {handshake_app_name} {self.port}") - end + # Respond to discovery requests sent over UDP + answer_discovery_requests # Setup clients var new_clients = accept_clients diff --git a/lib/gamnit/network/client.nit b/lib/gamnit/network/client.nit index 38db2db..8aad96f 100644 --- a/lib/gamnit/network/client.nit +++ b/lib/gamnit/network/client.nit @@ -40,7 +40,7 @@ # ~~~ module client -import common +intrude import common # Information of the remove server class RemoteServerConfig @@ -126,3 +126,55 @@ class RemoteServer return true end end + +# Discover local servers responding on UDP `discovery_port` +# +# Sends a message in the format `gamnit::network? handshake_app_name` and +# looks for the response `gamnit::network! handshake_app_name port_number`. +# Waits for `timeout`, or the default 0.1 seconds, after sending the message. +# +# The server usually responds using the method `answer_discovery_requests`. +# When receiving responses, the client may then choose a server and +# connect via `new RemoteServer`. +# +# ~~~ +# var servers = discover_local_servers +# if servers.not_empty then +# var server = new RemoteServer(servers.first) +# server.connect +# server.writer.serialize "hello server" +# server.socket.close +# end +# ~~~ +fun discover_local_servers(timeout: nullable Float): Array[RemoteServerConfig] +do + timeout = timeout or else 0.1 + + var s = new UDPSocket + s.enable_broadcast = true + s.blocking = false + s.broadcast(discovery_port, "{discovery_request_message} {handshake_app_name}") + timeout.sleep + + var r = new Array[RemoteServerConfig] + loop + var ptr = new Ref[nullable SocketAddress](null) + var resp = s.recv_from(1024, ptr) + var src = ptr.item + + if resp.is_empty then + # No response + break + else + assert src != null + var words = resp.split(" ") + if words.length == 3 and words[0] == discovery_response_message and + words[1] == handshake_app_name and words[2].is_int then + var address = src.address + var port = words[2].to_i + r.add new RemoteServerConfig(address, port) + end + end + end + return r +end diff --git a/lib/gamnit/network/common.nit b/lib/gamnit/network/common.nit index 54e764a..f534f1f 100644 --- a/lib/gamnit/network/common.nit +++ b/lib/gamnit/network/common.nit @@ -33,3 +33,14 @@ fun handshake_app_name: String do return program_name # # Both client and server refuse connections with a different version. fun handshake_app_version: String do return "0.0" + +# Server port listening for discovery requests +# +# This name must be the same between client/server. +fun discovery_port: Int do return 18722 + +# First word in discovery requests +private fun discovery_request_message: String do return "gamnit::network?" + +# First word in discovery responses +private fun discovery_response_message: String do return "gamnit::network!" diff --git a/lib/gamnit/network/server.nit b/lib/gamnit/network/server.nit index fcff7a2..926e620 100644 --- a/lib/gamnit/network/server.nit +++ b/lib/gamnit/network/server.nit @@ -45,7 +45,7 @@ # ~~~ module server -import common +intrude import common # Game server controller class Server @@ -56,15 +56,15 @@ class Server # All connected `RemoteClient` var clients = new Array[RemoteClient] - # Socket accepting new connections + # TCP socket accepting new connections + # + # Opened on the first call to `accept_clients`. var listening_socket: TCPServer is lazy do - print port var socket = new TCPServer(port) socket.listen 8 socket.blocking = false return socket end - init do listening_socket # Accept currently waiting clients and return them as an array fun accept_clients: Array[RemoteClient] @@ -98,6 +98,47 @@ class Server client.socket.flush end end + + # Respond to pending discovery requests by sending the TCP listening address and port + # + # Returns the number of valid requests received. + # + # The response messages includes the TCP listening address and port + # for remote clients to connect with TCP using `connect`. + # These connections are accepted by the server with `accept_clients`. + fun answer_discovery_requests: Int + do + var count = 0 + loop + var ptr = new Ref[nullable SocketAddress](null) + var read = discovery_socket.recv_from(1024, ptr) + + # No sender means there is no discovery request + var sender = ptr.item + if sender == null then break + + var words = read.split(" ") + if words.length != 2 or words[0] != discovery_request_message or words[1] != handshake_app_name then + print "Server Warning: Rejected discovery request '{read}' from {sender.address}:{sender.port}" + continue + end + + var msg = "{discovery_response_message} {handshake_app_name} {self.port}" + discovery_socket.send_to(sender.address, sender.port, msg) + count += 1 + end + return count + end + + # UDP socket responding to discovery requests + # + # Usually opened on the first call to `answer_discovery_request`. + var discovery_socket: UDPSocket is lazy do + var s = new UDPSocket + s.blocking = false + s.bind(null, discovery_port) + return s + end end # Reference to a remote client connected to this server -- 1.7.9.5