Browse Source

Implement NetworkedMultiplayerENet.get_local_port

Allows retrieving the local port to which the peer is bound.
Fabio Alessandrelli 4 years ago
parent
commit
cd22a2be2f

+ 9 - 2
modules/enet/doc_classes/NetworkedMultiplayerENet.xml

@@ -33,10 +33,10 @@
 			</argument>
 			</argument>
 			<argument index="3" name="out_bandwidth" type="int" default="0">
 			<argument index="3" name="out_bandwidth" type="int" default="0">
 			</argument>
 			</argument>
-			<argument index="4" name="client_port" type="int" default="0">
+			<argument index="4" name="local_port" type="int" default="0">
 			</argument>
 			</argument>
 			<description>
 			<description>
-				Create client that connects to a server at [code]address[/code] using specified [code]port[/code]. The given address needs to be either a fully qualified domain name (e.g. [code]"www.example.com"[/code]) or an IP address in IPv4 or IPv6 format (e.g. [code]"192.168.1.1"[/code]). The [code]port[/code] is the port the server is listening on. The [code]in_bandwidth[/code] and [code]out_bandwidth[/code] parameters can be used to limit the incoming and outgoing bandwidth to the given number of bytes per second. The default of 0 means unlimited bandwidth. Note that ENet will strategically drop packets on specific sides of a connection between peers to ensure the peer's bandwidth is not overwhelmed. The bandwidth parameters also determine the window size of a connection which limits the amount of reliable packets that may be in transit at any given time. Returns [constant OK] if a client was created, [constant ERR_ALREADY_IN_USE] if this NetworkedMultiplayerENet instance already has an open connection (in which case you need to call [method close_connection] first) or [constant ERR_CANT_CREATE] if the client could not be created. If [code]client_port[/code] is specified, the client will also listen to the given port; this is useful for some NAT traversal techniques.
+				Create client that connects to a server at [code]address[/code] using specified [code]port[/code]. The given address needs to be either a fully qualified domain name (e.g. [code]"www.example.com"[/code]) or an IP address in IPv4 or IPv6 format (e.g. [code]"192.168.1.1"[/code]). The [code]port[/code] is the port the server is listening on. The [code]in_bandwidth[/code] and [code]out_bandwidth[/code] parameters can be used to limit the incoming and outgoing bandwidth to the given number of bytes per second. The default of 0 means unlimited bandwidth. Note that ENet will strategically drop packets on specific sides of a connection between peers to ensure the peer's bandwidth is not overwhelmed. The bandwidth parameters also determine the window size of a connection which limits the amount of reliable packets that may be in transit at any given time. Returns [constant OK] if a client was created, [constant ERR_ALREADY_IN_USE] if this NetworkedMultiplayerENet instance already has an open connection (in which case you need to call [method close_connection] first) or [constant ERR_CANT_CREATE] if the client could not be created. If [code]local_port[/code] is specified, the client will also listen to the given port; this is useful for some NAT traversal techniques.
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="create_server">
 		<method name="create_server">
@@ -72,6 +72,13 @@
 				Returns the channel of the last packet fetched via [method PacketPeer.get_packet].
 				Returns the channel of the last packet fetched via [method PacketPeer.get_packet].
 			</description>
 			</description>
 		</method>
 		</method>
+		<method name="get_local_port" qualifiers="const">
+			<return type="int">
+			</return>
+			<description>
+				Returns the local port to which this peer is bound.
+			</description>
+		</method>
 		<method name="get_packet_channel" qualifiers="const">
 		<method name="get_packet_channel" qualifiers="const">
 			<return type="int">
 			<return type="int">
 			</return>
 			</return>

+ 29 - 32
modules/enet/networked_multiplayer_enet.cpp

@@ -68,7 +68,7 @@ int NetworkedMultiplayerENet::get_last_packet_channel() const {
 
 
 Error NetworkedMultiplayerENet::create_server(int p_port, int p_max_clients, int p_in_bandwidth, int p_out_bandwidth) {
 Error NetworkedMultiplayerENet::create_server(int p_port, int p_max_clients, int p_in_bandwidth, int p_out_bandwidth) {
 	ERR_FAIL_COND_V_MSG(active, ERR_ALREADY_IN_USE, "The multiplayer instance is already active.");
 	ERR_FAIL_COND_V_MSG(active, ERR_ALREADY_IN_USE, "The multiplayer instance is already active.");
-	ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The port number must be set between 0 and 65535 (inclusive).");
+	ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The local port number must be between 0 and 65535 (inclusive).");
 	ERR_FAIL_COND_V_MSG(p_max_clients < 1 || p_max_clients > 4095, ERR_INVALID_PARAMETER, "The number of clients must be set between 1 and 4095 (inclusive).");
 	ERR_FAIL_COND_V_MSG(p_max_clients < 1 || p_max_clients > 4095, ERR_INVALID_PARAMETER, "The number of clients must be set between 1 and 4095 (inclusive).");
 	ERR_FAIL_COND_V_MSG(p_in_bandwidth < 0, ERR_INVALID_PARAMETER, "The incoming bandwidth limit must be greater than or equal to 0 (0 disables the limit).");
 	ERR_FAIL_COND_V_MSG(p_in_bandwidth < 0, ERR_INVALID_PARAMETER, "The incoming bandwidth limit must be greater than or equal to 0 (0 disables the limit).");
 	ERR_FAIL_COND_V_MSG(p_out_bandwidth < 0, ERR_INVALID_PARAMETER, "The outgoing bandwidth limit must be greater than or equal to 0 (0 disables the limit).");
 	ERR_FAIL_COND_V_MSG(p_out_bandwidth < 0, ERR_INVALID_PARAMETER, "The outgoing bandwidth limit must be greater than or equal to 0 (0 disables the limit).");
@@ -115,46 +115,37 @@ Error NetworkedMultiplayerENet::create_server(int p_port, int p_max_clients, int
 	connection_status = CONNECTION_CONNECTED;
 	connection_status = CONNECTION_CONNECTED;
 	return OK;
 	return OK;
 }
 }
-
-Error NetworkedMultiplayerENet::create_client(const String &p_address, int p_port, int p_in_bandwidth, int p_out_bandwidth, int p_client_port) {
+Error NetworkedMultiplayerENet::create_client(const String &p_address, int p_port, int p_in_bandwidth, int p_out_bandwidth, int p_local_port) {
 	ERR_FAIL_COND_V_MSG(active, ERR_ALREADY_IN_USE, "The multiplayer instance is already active.");
 	ERR_FAIL_COND_V_MSG(active, ERR_ALREADY_IN_USE, "The multiplayer instance is already active.");
-	ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The server port number must be set between 0 and 65535 (inclusive).");
-	ERR_FAIL_COND_V_MSG(p_client_port < 0 || p_client_port > 65535, ERR_INVALID_PARAMETER, "The client port number must be set between 0 and 65535 (inclusive).");
+	ERR_FAIL_COND_V_MSG(p_port < 1 || p_port > 65535, ERR_INVALID_PARAMETER, "The remote port number must be between 1 and 65535 (inclusive).");
+	ERR_FAIL_COND_V_MSG(p_local_port < 0 || p_local_port > 65535, ERR_INVALID_PARAMETER, "The local port number must be between 0 and 65535 (inclusive).");
 	ERR_FAIL_COND_V_MSG(p_in_bandwidth < 0, ERR_INVALID_PARAMETER, "The incoming bandwidth limit must be greater than or equal to 0 (0 disables the limit).");
 	ERR_FAIL_COND_V_MSG(p_in_bandwidth < 0, ERR_INVALID_PARAMETER, "The incoming bandwidth limit must be greater than or equal to 0 (0 disables the limit).");
 	ERR_FAIL_COND_V_MSG(p_out_bandwidth < 0, ERR_INVALID_PARAMETER, "The outgoing bandwidth limit must be greater than or equal to 0 (0 disables the limit).");
 	ERR_FAIL_COND_V_MSG(p_out_bandwidth < 0, ERR_INVALID_PARAMETER, "The outgoing bandwidth limit must be greater than or equal to 0 (0 disables the limit).");
 
 
-	if (p_client_port != 0) {
-		ENetAddress c_client;
+	ENetAddress c_client;
 
 
 #ifdef GODOT_ENET
 #ifdef GODOT_ENET
-		if (bind_ip.is_wildcard()) {
-			c_client.wildcard = 1;
-		} else {
-			enet_address_set_ip(&c_client, bind_ip.get_ipv6(), 16);
-		}
+	if (bind_ip.is_wildcard()) {
+		c_client.wildcard = 1;
+	} else {
+		enet_address_set_ip(&c_client, bind_ip.get_ipv6(), 16);
+	}
 #else
 #else
-		if (bind_ip.is_wildcard()) {
-			c_client.host = 0;
-		} else {
-			ERR_FAIL_COND_V_MSG(!bind_ip.is_ipv4(), ERR_INVALID_PARAMETER, "Wildcard IP addresses are only permitted in IPv4, not IPv6.");
-			c_client.host = *(uint32_t *)bind_ip.get_ipv4();
-		}
+	if (bind_ip.is_wildcard()) {
+		c_client.host = 0;
+	} else {
+		ERR_FAIL_COND_V_MSG(!bind_ip.is_ipv4(), ERR_INVALID_PARAMETER, "Wildcard IP addresses are only permitted in IPv4, not IPv6.");
+		c_client.host = *(uint32_t *)bind_ip.get_ipv4();
+	}
 #endif
 #endif
 
 
-		c_client.port = p_client_port;
+	c_client.port = p_local_port;
 
 
-		host = enet_host_create(&c_client /* create a client host */,
-				1 /* only allow 1 outgoing connection */,
-				channel_count /* allow up to channel_count to be used */,
-				p_in_bandwidth /* limit incoming bandwidth if > 0 */,
-				p_out_bandwidth /* limit outgoing bandwidth if > 0 */);
-	} else {
-		host = enet_host_create(nullptr /* create a client host */,
-				1 /* only allow 1 outgoing connection */,
-				channel_count /* allow up to channel_count to be used */,
-				p_in_bandwidth /* limit incoming bandwidth if > 0 */,
-				p_out_bandwidth /* limit outgoing bandwidth if > 0 */);
-	}
+	host = enet_host_create(&c_client /* create a client host */,
+			1 /* only allow 1 outgoing connection */,
+			channel_count /* allow up to channel_count to be used */,
+			p_in_bandwidth /* limit incoming bandwidth if > 0 */,
+			p_out_bandwidth /* limit outgoing bandwidth if > 0 */);
 
 
 	ERR_FAIL_COND_V_MSG(!host, ERR_CANT_CREATE, "Couldn't create the ENet client host.");
 	ERR_FAIL_COND_V_MSG(!host, ERR_CANT_CREATE, "Couldn't create the ENet client host.");
 #ifdef GODOT_ENET
 #ifdef GODOT_ENET
@@ -784,6 +775,11 @@ int NetworkedMultiplayerENet::get_peer_port(int p_peer_id) const {
 #endif
 #endif
 }
 }
 
 
+int NetworkedMultiplayerENet::get_local_port() const {
+	ERR_FAIL_COND_V_MSG(!active || !host, 0, "The multiplayer instance isn't currently active.");
+	return host->address.port;
+}
+
 void NetworkedMultiplayerENet::set_peer_timeout(int p_peer_id, int p_timeout_limit, int p_timeout_min, int p_timeout_max) {
 void NetworkedMultiplayerENet::set_peer_timeout(int p_peer_id, int p_timeout_limit, int p_timeout_min, int p_timeout_max) {
 	ERR_FAIL_COND_MSG(!peer_map.has(p_peer_id), vformat("Peer ID %d not found in the list of peers.", p_peer_id));
 	ERR_FAIL_COND_MSG(!peer_map.has(p_peer_id), vformat("Peer ID %d not found in the list of peers.", p_peer_id));
 	ERR_FAIL_COND_MSG(!is_server() && p_peer_id != 1, "Can't change the timeout of peers other then the server when acting as a client.");
 	ERR_FAIL_COND_MSG(!is_server() && p_peer_id != 1, "Can't change the timeout of peers other then the server when acting as a client.");
@@ -832,7 +828,7 @@ bool NetworkedMultiplayerENet::is_server_relay_enabled() const {
 
 
 void NetworkedMultiplayerENet::_bind_methods() {
 void NetworkedMultiplayerENet::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("create_server", "port", "max_clients", "in_bandwidth", "out_bandwidth"), &NetworkedMultiplayerENet::create_server, DEFVAL(32), DEFVAL(0), DEFVAL(0));
 	ClassDB::bind_method(D_METHOD("create_server", "port", "max_clients", "in_bandwidth", "out_bandwidth"), &NetworkedMultiplayerENet::create_server, DEFVAL(32), DEFVAL(0), DEFVAL(0));
-	ClassDB::bind_method(D_METHOD("create_client", "address", "port", "in_bandwidth", "out_bandwidth", "client_port"), &NetworkedMultiplayerENet::create_client, DEFVAL(0), DEFVAL(0), DEFVAL(0));
+	ClassDB::bind_method(D_METHOD("create_client", "address", "port", "in_bandwidth", "out_bandwidth", "local_port"), &NetworkedMultiplayerENet::create_client, DEFVAL(0), DEFVAL(0), DEFVAL(0));
 	ClassDB::bind_method(D_METHOD("close_connection", "wait_usec"), &NetworkedMultiplayerENet::close_connection, DEFVAL(100));
 	ClassDB::bind_method(D_METHOD("close_connection", "wait_usec"), &NetworkedMultiplayerENet::close_connection, DEFVAL(100));
 	ClassDB::bind_method(D_METHOD("disconnect_peer", "id", "now"), &NetworkedMultiplayerENet::disconnect_peer, DEFVAL(false));
 	ClassDB::bind_method(D_METHOD("disconnect_peer", "id", "now"), &NetworkedMultiplayerENet::disconnect_peer, DEFVAL(false));
 	ClassDB::bind_method(D_METHOD("set_compression_mode", "mode"), &NetworkedMultiplayerENet::set_compression_mode);
 	ClassDB::bind_method(D_METHOD("set_compression_mode", "mode"), &NetworkedMultiplayerENet::set_compression_mode);
@@ -846,6 +842,7 @@ void NetworkedMultiplayerENet::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("is_dtls_verify_enabled"), &NetworkedMultiplayerENet::is_dtls_verify_enabled);
 	ClassDB::bind_method(D_METHOD("is_dtls_verify_enabled"), &NetworkedMultiplayerENet::is_dtls_verify_enabled);
 	ClassDB::bind_method(D_METHOD("get_peer_address", "id"), &NetworkedMultiplayerENet::get_peer_address);
 	ClassDB::bind_method(D_METHOD("get_peer_address", "id"), &NetworkedMultiplayerENet::get_peer_address);
 	ClassDB::bind_method(D_METHOD("get_peer_port", "id"), &NetworkedMultiplayerENet::get_peer_port);
 	ClassDB::bind_method(D_METHOD("get_peer_port", "id"), &NetworkedMultiplayerENet::get_peer_port);
+	ClassDB::bind_method(D_METHOD("get_local_port"), &NetworkedMultiplayerENet::get_local_port);
 	ClassDB::bind_method(D_METHOD("set_peer_timeout", "id", "timeout_limit", "timeout_min", "timeout_max"), &NetworkedMultiplayerENet::set_peer_timeout);
 	ClassDB::bind_method(D_METHOD("set_peer_timeout", "id", "timeout_limit", "timeout_min", "timeout_max"), &NetworkedMultiplayerENet::set_peer_timeout);
 
 
 	ClassDB::bind_method(D_METHOD("get_packet_channel"), &NetworkedMultiplayerENet::get_packet_channel);
 	ClassDB::bind_method(D_METHOD("get_packet_channel"), &NetworkedMultiplayerENet::get_packet_channel);

+ 2 - 1
modules/enet/networked_multiplayer_enet.h

@@ -127,10 +127,11 @@ public:
 
 
 	virtual IP_Address get_peer_address(int p_peer_id) const;
 	virtual IP_Address get_peer_address(int p_peer_id) const;
 	virtual int get_peer_port(int p_peer_id) const;
 	virtual int get_peer_port(int p_peer_id) const;
+	virtual int get_local_port() const;
 	void set_peer_timeout(int p_peer_id, int p_timeout_limit, int p_timeout_min, int p_timeout_max);
 	void set_peer_timeout(int p_peer_id, int p_timeout_limit, int p_timeout_min, int p_timeout_max);
 
 
 	Error create_server(int p_port, int p_max_clients = 32, int p_in_bandwidth = 0, int p_out_bandwidth = 0);
 	Error create_server(int p_port, int p_max_clients = 32, int p_in_bandwidth = 0, int p_out_bandwidth = 0);
-	Error create_client(const String &p_address, int p_port, int p_in_bandwidth = 0, int p_out_bandwidth = 0, int p_client_port = 0);
+	Error create_client(const String &p_address, int p_port, int p_in_bandwidth = 0, int p_out_bandwidth = 0, int p_local_port = 0);
 
 
 	void close_connection(uint32_t wait_usec = 100);
 	void close_connection(uint32_t wait_usec = 100);
 
 

+ 55 - 13
thirdparty/enet/godot.cpp

@@ -46,6 +46,7 @@
 class ENetGodotSocket {
 class ENetGodotSocket {
 public:
 public:
 	virtual Error bind(IP_Address p_ip, uint16_t p_port) = 0;
 	virtual Error bind(IP_Address p_ip, uint16_t p_port) = 0;
+	virtual Error get_socket_address(IP_Address *r_ip, uint16_t *r_port) = 0;
 	virtual Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) = 0;
 	virtual Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) = 0;
 	virtual Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port) = 0;
 	virtual Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port) = 0;
 	virtual int set_option(ENetSocketOption p_option, int p_value) = 0;
 	virtual int set_option(ENetSocketOption p_option, int p_value) = 0;
@@ -64,8 +65,7 @@ class ENetUDP : public ENetGodotSocket {
 
 
 private:
 private:
 	Ref<NetSocket> sock;
 	Ref<NetSocket> sock;
-	IP_Address address;
-	uint16_t port = 0;
+	IP_Address local_address;
 	bool bound = false;
 	bool bound = false;
 
 
 public:
 public:
@@ -80,10 +80,13 @@ public:
 	}
 	}
 
 
 	Error bind(IP_Address p_ip, uint16_t p_port) {
 	Error bind(IP_Address p_ip, uint16_t p_port) {
-		address = p_ip;
-		port = p_port;
+		local_address = p_ip;
 		bound = true;
 		bound = true;
-		return sock->bind(address, port);
+		return sock->bind(p_ip, p_port);
+	}
+
+	Error get_socket_address(IP_Address *r_ip, uint16_t *r_port) {
+		return sock->get_socket_address(r_ip, r_port);
 	}
 	}
 
 
 	Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) {
 	Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) {
@@ -142,6 +145,7 @@ public:
 
 
 	void close() {
 	void close() {
 		sock->close();
 		sock->close();
+		local_address.clear();
 	}
 	}
 };
 };
 
 
@@ -153,6 +157,7 @@ class ENetDTLSClient : public ENetGodotSocket {
 	bool verify = false;
 	bool verify = false;
 	String for_hostname;
 	String for_hostname;
 	Ref<X509Certificate> cert;
 	Ref<X509Certificate> cert;
+	IP_Address local_address;
 
 
 public:
 public:
 	ENetDTLSClient(ENetUDP *p_base, Ref<X509Certificate> p_cert, bool p_verify, String p_for_hostname) {
 	ENetDTLSClient(ENetUDP *p_base, Ref<X509Certificate> p_cert, bool p_verify, String p_for_hostname) {
@@ -161,9 +166,11 @@ public:
 		cert = p_cert;
 		cert = p_cert;
 		udp.instance();
 		udp.instance();
 		dtls = Ref<PacketPeerDTLS>(PacketPeerDTLS::create());
 		dtls = Ref<PacketPeerDTLS>(PacketPeerDTLS::create());
-		p_base->close();
 		if (p_base->bound) {
 		if (p_base->bound) {
-			bind(p_base->address, p_base->port);
+			uint16_t port;
+			p_base->get_socket_address(&local_address, &port);
+			p_base->close();
+			bind(local_address, port);
 		}
 		}
 	}
 	}
 
 
@@ -172,9 +179,19 @@ public:
 	}
 	}
 
 
 	Error bind(IP_Address p_ip, uint16_t p_port) {
 	Error bind(IP_Address p_ip, uint16_t p_port) {
+		local_address = p_ip;
 		return udp->bind(p_port, p_ip);
 		return udp->bind(p_port, p_ip);
 	}
 	}
 
 
+	Error get_socket_address(IP_Address *r_ip, uint16_t *r_port) {
+		if (!udp->is_bound()) {
+			return ERR_UNCONFIGURED;
+		}
+		*r_ip = local_address;
+		*r_port = udp->get_local_port();
+		return OK;
+	}
+
 	Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) {
 	Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) {
 		if (!connected) {
 		if (!connected) {
 			udp->connect_to_host(p_ip, p_port);
 			udp->connect_to_host(p_ip, p_port);
@@ -233,13 +250,16 @@ class ENetDTLSServer : public ENetGodotSocket {
 	Ref<UDPServer> udp_server;
 	Ref<UDPServer> udp_server;
 	Map<String, Ref<PacketPeerDTLS>> peers;
 	Map<String, Ref<PacketPeerDTLS>> peers;
 	int last_service = 0;
 	int last_service = 0;
+	IP_Address local_address;
 
 
 public:
 public:
 	ENetDTLSServer(ENetUDP *p_base, Ref<CryptoKey> p_key, Ref<X509Certificate> p_cert) {
 	ENetDTLSServer(ENetUDP *p_base, Ref<CryptoKey> p_key, Ref<X509Certificate> p_cert) {
 		udp_server.instance();
 		udp_server.instance();
-		p_base->close();
 		if (p_base->bound) {
 		if (p_base->bound) {
-			bind(p_base->address, p_base->port);
+			uint16_t port;
+			p_base->get_socket_address(&local_address, &port);
+			p_base->close();
+			bind(local_address, port);
 		}
 		}
 		server = Ref<DTLSServer>(DTLSServer::create());
 		server = Ref<DTLSServer>(DTLSServer::create());
 		server->setup(p_key, p_cert);
 		server->setup(p_key, p_cert);
@@ -254,9 +274,19 @@ public:
 	}
 	}
 
 
 	Error bind(IP_Address p_ip, uint16_t p_port) {
 	Error bind(IP_Address p_ip, uint16_t p_port) {
+		local_address = p_ip;
 		return udp_server->listen(p_port, p_ip);
 		return udp_server->listen(p_port, p_ip);
 	}
 	}
 
 
+	Error get_socket_address(IP_Address *r_ip, uint16_t *r_port) {
+		if (!udp_server->is_listening()) {
+			return ERR_UNCONFIGURED;
+		}
+		*r_ip = local_address;
+		*r_port = udp_server->get_local_port();
+		return OK;
+	}
+
 	Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) {
 	Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) {
 		String key = String(p_ip) + ":" + itos(p_port);
 		String key = String(p_ip) + ":" + itos(p_port);
 		ERR_FAIL_COND_V(!peers.has(key), ERR_UNAVAILABLE);
 		ERR_FAIL_COND_V(!peers.has(key), ERR_UNAVAILABLE);
@@ -341,6 +371,7 @@ public:
 		peers.clear();
 		peers.clear();
 		udp_server->stop();
 		udp_server->stop();
 		server->stop();
 		server->stop();
+		local_address.clear();
 	}
 	}
 };
 };
 
 
@@ -493,15 +524,26 @@ int enet_socket_receive(ENetSocket socket, ENetAddress *address, ENetBuffer *buf
 	return read;
 	return read;
 }
 }
 
 
+int enet_socket_get_address (ENetSocket socket, ENetAddress * address) {
+	IP_Address ip;
+	uint16_t port;
+	ENetGodotSocket *sock = (ENetGodotSocket *)socket;
+
+	if (sock->get_socket_address(&ip, &port) != OK) {
+		return -1;
+	}
+
+	enet_address_set_ip(address, ip.get_ipv6(), 16);
+	address->port = port;
+
+	return 0;
+}
+
 // Not implemented
 // Not implemented
 int enet_socket_wait(ENetSocket socket, enet_uint32 *condition, enet_uint32 timeout) {
 int enet_socket_wait(ENetSocket socket, enet_uint32 *condition, enet_uint32 timeout) {
 	return 0; // do we need this function?
 	return 0; // do we need this function?
 }
 }
 
 
-int enet_socket_get_address(ENetSocket socket, ENetAddress *address) {
-	return -1; // do we need this function?
-}
-
 int enet_socketset_select(ENetSocket maxSocket, ENetSocketSet *readSet, ENetSocketSet *writeSet, enet_uint32 timeout) {
 int enet_socketset_select(ENetSocket maxSocket, ENetSocketSet *readSet, ENetSocketSet *writeSet, enet_uint32 timeout) {
 	return -1;
 	return -1;
 }
 }