Skip to content

Commit

Permalink
Merge pull request #47398 from Faless/feature/network-local-port-salv…
Browse files Browse the repository at this point in the history
…aged
  • Loading branch information
akien-mga authored Apr 27, 2021
2 parents 2a1f3c4 + 4d5c8e0 commit 72bd64c
Show file tree
Hide file tree
Showing 16 changed files with 192 additions and 66 deletions.
1 change: 1 addition & 0 deletions core/io/net_socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class NetSocket : public Reference {

virtual bool is_open() const = 0;
virtual int get_available_bytes() const = 0;
virtual Error get_socket_address(IP_Address *r_ip, uint16_t *r_port) const = 0;

virtual Error set_broadcasting_enabled(bool p_enabled) = 0; // Returns OK if the socket option has been set successfully.
virtual void set_blocking_enabled(bool p_enabled) = 0;
Expand Down
17 changes: 13 additions & 4 deletions core/io/packet_peer_udp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,11 @@ int PacketPeerUDP::get_max_packet_size() const {
return 512; // uhm maybe not
}

Error PacketPeerUDP::listen(int p_port, const IP_Address &p_bind_address, int p_recv_buffer_size) {
Error PacketPeerUDP::bind(int p_port, const IP_Address &p_bind_address, int p_recv_buffer_size) {
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(_sock->is_open(), ERR_ALREADY_IN_USE);
ERR_FAIL_COND_V(!p_bind_address.is_valid() && !p_bind_address.is_wildcard(), ERR_INVALID_PARAMETER);
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).");

Error err;
IP::Type ip_type = IP::TYPE_ANY;
Expand Down Expand Up @@ -210,6 +211,7 @@ Error PacketPeerUDP::connect_to_host(const IP_Address &p_host, int p_port) {
ERR_FAIL_COND_V(udp_server, ERR_LOCKED);
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(!p_host.is_valid(), ERR_INVALID_PARAMETER);
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).");

Error err;

Expand Down Expand Up @@ -316,7 +318,7 @@ Error PacketPeerUDP::store_packet(IP_Address p_ip, uint32_t p_port, uint8_t *p_b
return OK;
}

bool PacketPeerUDP::is_listening() const {
bool PacketPeerUDP::is_bound() const {
return _sock.is_valid() && _sock->is_open();
}

Expand All @@ -328,21 +330,28 @@ int PacketPeerUDP::get_packet_port() const {
return packet_port;
}

int PacketPeerUDP::get_local_port() const {
uint16_t local_port;
_sock->get_socket_address(nullptr, &local_port);
return local_port;
}

void PacketPeerUDP::set_dest_address(const IP_Address &p_address, int p_port) {
ERR_FAIL_COND_MSG(connected, "Destination address cannot be set for connected sockets");
peer_addr = p_address;
peer_port = p_port;
}

void PacketPeerUDP::_bind_methods() {
ClassDB::bind_method(D_METHOD("listen", "port", "bind_address", "recv_buf_size"), &PacketPeerUDP::listen, DEFVAL("*"), DEFVAL(65536));
ClassDB::bind_method(D_METHOD("bind", "port", "bind_address", "recv_buf_size"), &PacketPeerUDP::bind, DEFVAL("*"), DEFVAL(65536));
ClassDB::bind_method(D_METHOD("close"), &PacketPeerUDP::close);
ClassDB::bind_method(D_METHOD("wait"), &PacketPeerUDP::wait);
ClassDB::bind_method(D_METHOD("is_listening"), &PacketPeerUDP::is_listening);
ClassDB::bind_method(D_METHOD("is_bound"), &PacketPeerUDP::is_bound);
ClassDB::bind_method(D_METHOD("connect_to_host", "host", "port"), &PacketPeerUDP::connect_to_host);
ClassDB::bind_method(D_METHOD("is_connected_to_host"), &PacketPeerUDP::is_connected_to_host);
ClassDB::bind_method(D_METHOD("get_packet_ip"), &PacketPeerUDP::_get_packet_ip);
ClassDB::bind_method(D_METHOD("get_packet_port"), &PacketPeerUDP::get_packet_port);
ClassDB::bind_method(D_METHOD("get_local_port"), &PacketPeerUDP::get_local_port);
ClassDB::bind_method(D_METHOD("set_dest_address", "host", "port"), &PacketPeerUDP::_set_dest_address);
ClassDB::bind_method(D_METHOD("set_broadcast_enabled", "enabled"), &PacketPeerUDP::set_broadcast_enabled);
ClassDB::bind_method(D_METHOD("join_multicast_group", "multicast_address", "interface_name"), &PacketPeerUDP::join_multicast_group);
Expand Down
5 changes: 3 additions & 2 deletions core/io/packet_peer_udp.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,10 @@ class PacketPeerUDP : public PacketPeer {
public:
void set_blocking_mode(bool p_enable);

Error listen(int p_port, const IP_Address &p_bind_address = IP_Address("*"), int p_recv_buffer_size = 65536);
Error bind(int p_port, const IP_Address &p_bind_address = IP_Address("*"), int p_recv_buffer_size = 65536);
void close();
Error wait();
bool is_listening() const;
bool is_bound() const;

Error connect_shared_socket(Ref<NetSocket> p_sock, IP_Address p_ip, uint16_t p_port, UDPServer *ref); // Used by UDPServer
void disconnect_shared_socket(); // Used by UDPServer
Expand All @@ -83,6 +83,7 @@ class PacketPeerUDP : public PacketPeer {

IP_Address get_packet_address() const;
int get_packet_port() const;
int get_local_port() const;
void set_dest_address(const IP_Address &p_address, int p_port);

Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override;
Expand Down
43 changes: 35 additions & 8 deletions core/io/stream_peer_tcp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,21 +67,40 @@ void StreamPeerTCP::accept_socket(Ref<NetSocket> p_sock, IP_Address p_host, uint
peer_port = p_port;
}

Error StreamPeerTCP::connect_to_host(const IP_Address &p_host, uint16_t p_port) {
Error StreamPeerTCP::bind(int p_port, const IP_Address &p_host) {
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(_sock->is_open(), ERR_ALREADY_IN_USE);
ERR_FAIL_COND_V(!p_host.is_valid(), ERR_INVALID_PARAMETER);
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).");

Error err;
IP::Type ip_type = p_host.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6;
if (p_host.is_wildcard()) {
ip_type = IP::TYPE_ANY;
}
Error err = _sock->open(NetSocket::TYPE_TCP, ip_type);
if (err != OK) {
return err;
}
_sock->set_blocking_enabled(false);
return _sock->bind(p_host, p_port);
}

err = _sock->open(NetSocket::TYPE_TCP, ip_type);
ERR_FAIL_COND_V(err != OK, FAILED);
Error StreamPeerTCP::connect_to_host(const IP_Address &p_host, int p_port) {
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(status != STATUS_NONE, ERR_ALREADY_IN_USE);
ERR_FAIL_COND_V(!p_host.is_valid(), ERR_INVALID_PARAMETER);
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).");

_sock->set_blocking_enabled(false);
if (!_sock->is_open()) {
IP::Type ip_type = p_host.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6;
Error err = _sock->open(NetSocket::TYPE_TCP, ip_type);
if (err != OK) {
return err;
}
_sock->set_blocking_enabled(false);
}

timeout = OS::get_singleton()->get_ticks_msec() + (((uint64_t)GLOBAL_GET("network/limits/tcp/connect_timeout_seconds")) * 1000);
err = _sock->connect_to_host(p_host, p_port);
Error err = _sock->connect_to_host(p_host, p_port);

if (err == OK) {
status = STATUS_CONNECTED;
Expand Down Expand Up @@ -300,10 +319,16 @@ IP_Address StreamPeerTCP::get_connected_host() const {
return peer_host;
}

uint16_t StreamPeerTCP::get_connected_port() const {
int StreamPeerTCP::get_connected_port() const {
return peer_port;
}

int StreamPeerTCP::get_local_port() const {
uint16_t local_port;
_sock->get_socket_address(nullptr, &local_port);
return local_port;
}

Error StreamPeerTCP::_connect(const String &p_address, int p_port) {
IP_Address ip;
if (p_address.is_valid_ip_address()) {
Expand All @@ -319,11 +344,13 @@ Error StreamPeerTCP::_connect(const String &p_address, int p_port) {
}

void StreamPeerTCP::_bind_methods() {
ClassDB::bind_method(D_METHOD("bind", "port", "host"), &StreamPeerTCP::bind, DEFVAL("*"));
ClassDB::bind_method(D_METHOD("connect_to_host", "host", "port"), &StreamPeerTCP::_connect);
ClassDB::bind_method(D_METHOD("is_connected_to_host"), &StreamPeerTCP::is_connected_to_host);
ClassDB::bind_method(D_METHOD("get_status"), &StreamPeerTCP::get_status);
ClassDB::bind_method(D_METHOD("get_connected_host"), &StreamPeerTCP::get_connected_host);
ClassDB::bind_method(D_METHOD("get_connected_port"), &StreamPeerTCP::get_connected_port);
ClassDB::bind_method(D_METHOD("get_local_port"), &StreamPeerTCP::get_local_port);
ClassDB::bind_method(D_METHOD("disconnect_from_host"), &StreamPeerTCP::disconnect_from_host);
ClassDB::bind_method(D_METHOD("set_no_delay", "enabled"), &StreamPeerTCP::set_no_delay);

Expand Down
6 changes: 4 additions & 2 deletions core/io/stream_peer_tcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,12 @@ class StreamPeerTCP : public StreamPeer {
public:
void accept_socket(Ref<NetSocket> p_sock, IP_Address p_host, uint16_t p_port);

Error connect_to_host(const IP_Address &p_host, uint16_t p_port);
Error bind(int p_port, const IP_Address &p_host);
Error connect_to_host(const IP_Address &p_host, int p_port);
bool is_connected_to_host() const;
IP_Address get_connected_host() const;
uint16_t get_connected_port() const;
int get_connected_port() const;
int get_local_port() const;
void disconnect_from_host();

int get_available_bytes() const override;
Expand Down
8 changes: 8 additions & 0 deletions core/io/tcp_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ void TCP_Server::_bind_methods() {
ClassDB::bind_method(D_METHOD("listen", "port", "bind_address"), &TCP_Server::listen, DEFVAL("*"));
ClassDB::bind_method(D_METHOD("is_connection_available"), &TCP_Server::is_connection_available);
ClassDB::bind_method(D_METHOD("is_listening"), &TCP_Server::is_listening);
ClassDB::bind_method(D_METHOD("get_local_port"), &TCP_Server::get_local_port);
ClassDB::bind_method(D_METHOD("take_connection"), &TCP_Server::take_connection);
ClassDB::bind_method(D_METHOD("stop"), &TCP_Server::stop);
}
Expand All @@ -42,6 +43,7 @@ Error TCP_Server::listen(uint16_t p_port, const IP_Address &p_bind_address) {
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(_sock->is_open(), ERR_ALREADY_IN_USE);
ERR_FAIL_COND_V(!p_bind_address.is_valid() && !p_bind_address.is_wildcard(), ERR_INVALID_PARAMETER);
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).");

Error err;
IP::Type ip_type = IP::TYPE_ANY;
Expand Down Expand Up @@ -74,6 +76,12 @@ Error TCP_Server::listen(uint16_t p_port, const IP_Address &p_bind_address) {
return OK;
}

int TCP_Server::get_local_port() const {
uint16_t local_port;
_sock->get_socket_address(nullptr, &local_port);
return local_port;
}

bool TCP_Server::is_listening() const {
ERR_FAIL_COND_V(!_sock.is_valid(), false);

Expand Down
1 change: 1 addition & 0 deletions core/io/tcp_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class TCP_Server : public Reference {

public:
Error listen(uint16_t p_port, const IP_Address &p_bind_address = IP_Address("*"));
int get_local_port() const;
bool is_listening() const;
bool is_connection_available() const;
Ref<StreamPeerTCP> take_connection();
Expand Down
12 changes: 8 additions & 4 deletions core/io/udp_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ void UDPServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("listen", "port", "bind_address"), &UDPServer::listen, DEFVAL("*"));
ClassDB::bind_method(D_METHOD("poll"), &UDPServer::poll);
ClassDB::bind_method(D_METHOD("is_connection_available"), &UDPServer::is_connection_available);
ClassDB::bind_method(D_METHOD("get_local_port"), &UDPServer::get_local_port);
ClassDB::bind_method(D_METHOD("is_listening"), &UDPServer::is_listening);
ClassDB::bind_method(D_METHOD("take_connection"), &UDPServer::take_connection);
ClassDB::bind_method(D_METHOD("stop"), &UDPServer::stop);
Expand Down Expand Up @@ -90,6 +91,7 @@ Error UDPServer::listen(uint16_t p_port, const IP_Address &p_bind_address) {
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(_sock->is_open(), ERR_ALREADY_IN_USE);
ERR_FAIL_COND_V(!p_bind_address.is_valid() && !p_bind_address.is_wildcard(), ERR_INVALID_PARAMETER);
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).");

Error err;
IP::Type ip_type = IP::TYPE_ANY;
Expand All @@ -112,11 +114,15 @@ Error UDPServer::listen(uint16_t p_port, const IP_Address &p_bind_address) {
stop();
return err;
}
bind_address = p_bind_address;
bind_port = p_port;
return OK;
}

int UDPServer::get_local_port() const {
uint16_t local_port;
_sock->get_socket_address(nullptr, &local_port);
return local_port;
}

bool UDPServer::is_listening() const {
ERR_FAIL_COND_V(!_sock.is_valid(), false);

Expand Down Expand Up @@ -176,8 +182,6 @@ void UDPServer::stop() {
if (_sock.is_valid()) {
_sock->close();
}
bind_port = 0;
bind_address = IP_Address();
List<Peer>::Element *E = peers.front();
while (E) {
E->get().peer->disconnect_shared_socket();
Expand Down
5 changes: 1 addition & 4 deletions core/io/udp_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,21 +53,18 @@ class UDPServer : public Reference {
};
uint8_t recv_buffer[PACKET_BUFFER_SIZE];

int bind_port = 0;
IP_Address bind_address;

List<Peer> peers;
List<Peer> pending;
int max_pending_connections = 16;

Ref<NetSocket> _sock;

static void _bind_methods();

public:
void remove_peer(IP_Address p_ip, int p_port);
Error listen(uint16_t p_port, const IP_Address &p_bind_address = IP_Address("*"));
Error poll();
int get_local_port() const;
bool is_listening() const;
bool is_connection_available() const;
void set_max_pending_connections(int p_max);
Expand Down
51 changes: 29 additions & 22 deletions doc/classes/PacketPeerUDP.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,27 @@
<tutorials>
</tutorials>
<methods>
<method name="bind">
<return type="int" enum="Error">
</return>
<argument index="0" name="port" type="int">
</argument>
<argument index="1" name="bind_address" type="String" default="&quot;*&quot;">
</argument>
<argument index="2" name="recv_buf_size" type="int" default="65536">
</argument>
<description>
Binds this [PacketPeerUDP] to the specified [code]port[/code] and [code]address[/code] with a buffer size [code]recv_buf_size[/code], allowing it to receive incoming packets.
If [code]address[/code] is set to [code]"*"[/code] (default), the peer will be bound on all available addresses (both IPv4 and IPv6).
If [code]address[/code] is set to [code]"0.0.0.0"[/code] (for IPv4) or [code]"::"[/code] (for IPv6), the peer will be bound to all available addresses matching that IP type.
If [code]address[/code] is set to any valid address (e.g. [code]"192.168.1.101"[/code], [code]"::1"[/code], etc), the peer will only be bound to the interface with that addresses (or fail if no interface with the given address exists).
</description>
</method>
<method name="close">
<return type="void">
</return>
<description>
Closes the UDP socket the [PacketPeerUDP] is currently listening on.
Closes the [PacketPeerUDP]'s underlying UDP socket.
</description>
</method>
<method name="connect_to_host">
Expand All @@ -28,6 +44,13 @@
[b]Note:[/b] Connecting to the remote peer does not help to protect from malicious attacks like IP spoofing, etc. Think about using an encryption technique like SSL or DTLS if you feel like your application is transferring sensitive information.
</description>
</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_ip" qualifiers="const">
<return type="String">
</return>
Expand All @@ -42,18 +65,18 @@
Returns the port of the remote peer that sent the last packet(that was received with [method PacketPeer.get_packet] or [method PacketPeer.get_var]).
</description>
</method>
<method name="is_connected_to_host" qualifiers="const">
<method name="is_bound" qualifiers="const">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if the UDP socket is open and has been connected to a remote address. See [method connect_to_host].
Returns whether this [PacketPeerUDP] is bound to an address and can receive packets.
</description>
</method>
<method name="is_listening" qualifiers="const">
<method name="is_connected_to_host" qualifiers="const">
<return type="bool">
</return>
<description>
Returns whether this [PacketPeerUDP] is listening.
Returns [code]true[/code] if the UDP socket is open and has been connected to a remote address. See [method connect_to_host].
</description>
</method>
<method name="join_multicast_group">
Expand All @@ -80,22 +103,6 @@
Removes the interface identified by [code]interface_name[/code] from the multicast group specified by [code]multicast_address[/code].
</description>
</method>
<method name="listen">
<return type="int" enum="Error">
</return>
<argument index="0" name="port" type="int">
</argument>
<argument index="1" name="bind_address" type="String" default="&quot;*&quot;">
</argument>
<argument index="2" name="recv_buf_size" type="int" default="65536">
</argument>
<description>
Makes this [PacketPeerUDP] listen on the [code]port[/code] binding to [code]bind_address[/code] with a buffer size [code]recv_buf_size[/code].
If [code]bind_address[/code] is set to [code]"*"[/code] (default), the peer will listen on all available addresses (both IPv4 and IPv6).
If [code]bind_address[/code] is set to [code]"0.0.0.0"[/code] (for IPv4) or [code]"::"[/code] (for IPv6), the peer will listen on all available addresses matching that IP type.
If [code]bind_address[/code] is set to any valid address (e.g. [code]"192.168.1.101"[/code], [code]"::1"[/code], etc), the peer will only listen on the interface with that addresses (or fail if no interface with the given address exists).
</description>
</method>
<method name="set_broadcast_enabled">
<return type="void">
</return>
Expand All @@ -122,7 +129,7 @@
<return type="int" enum="Error">
</return>
<description>
Waits for a packet to arrive on the listening port. See [method listen].
Waits for a packet to arrive on the bound address. See [method bind].
[b]Note:[/b] [method wait] can't be interrupted once it has been called. This can be worked around by allowing the other party to send a specific "death pill" packet like this:
[codeblocks]
[gdscript]
Expand Down
Loading

0 comments on commit 72bd64c

Please sign in to comment.