Merge pull request #47398 from Faless/feature/network-local-port-salvaged

This commit is contained in:
Rémi Verschelde 2021-04-27 15:04:30 +02:00 committed by GitHub
commit 72bd64c1d5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 196 additions and 70 deletions

View file

@ -67,6 +67,7 @@ public:
virtual bool is_open() const = 0; virtual bool is_open() const = 0;
virtual int get_available_bytes() 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 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; virtual void set_blocking_enabled(bool p_enabled) = 0;

View file

@ -159,10 +159,11 @@ int PacketPeerUDP::get_max_packet_size() const {
return 512; // uhm maybe not 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_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(_sock->is_open(), ERR_ALREADY_IN_USE); 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(!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; Error err;
IP::Type ip_type = IP::TYPE_ANY; IP::Type ip_type = IP::TYPE_ANY;
@ -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(udp_server, ERR_LOCKED);
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE); ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(!p_host.is_valid(), ERR_INVALID_PARAMETER); 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; Error err;
@ -316,7 +318,7 @@ Error PacketPeerUDP::store_packet(IP_Address p_ip, uint32_t p_port, uint8_t *p_b
return OK; return OK;
} }
bool PacketPeerUDP::is_listening() const { bool PacketPeerUDP::is_bound() const {
return _sock.is_valid() && _sock->is_open(); return _sock.is_valid() && _sock->is_open();
} }
@ -328,6 +330,12 @@ int PacketPeerUDP::get_packet_port() const {
return packet_port; 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) { 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"); ERR_FAIL_COND_MSG(connected, "Destination address cannot be set for connected sockets");
peer_addr = p_address; peer_addr = p_address;
@ -335,14 +343,15 @@ void PacketPeerUDP::set_dest_address(const IP_Address &p_address, int p_port) {
} }
void PacketPeerUDP::_bind_methods() { 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("close"), &PacketPeerUDP::close);
ClassDB::bind_method(D_METHOD("wait"), &PacketPeerUDP::wait); 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("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("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_ip"), &PacketPeerUDP::_get_packet_ip);
ClassDB::bind_method(D_METHOD("get_packet_port"), &PacketPeerUDP::get_packet_port); 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_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("set_broadcast_enabled", "enabled"), &PacketPeerUDP::set_broadcast_enabled);
ClassDB::bind_method(D_METHOD("join_multicast_group", "multicast_address", "interface_name"), &PacketPeerUDP::join_multicast_group); ClassDB::bind_method(D_METHOD("join_multicast_group", "multicast_address", "interface_name"), &PacketPeerUDP::join_multicast_group);

View file

@ -70,10 +70,10 @@ protected:
public: public:
void set_blocking_mode(bool p_enable); 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(); void close();
Error wait(); 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 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 void disconnect_shared_socket(); // Used by UDPServer
@ -83,6 +83,7 @@ public:
IP_Address get_packet_address() const; IP_Address get_packet_address() const;
int get_packet_port() const; int get_packet_port() const;
int get_local_port() const;
void set_dest_address(const IP_Address &p_address, int p_port); 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; Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override;

View file

@ -67,21 +67,40 @@ void StreamPeerTCP::accept_socket(Ref<NetSocket> p_sock, IP_Address p_host, uint
peer_port = p_port; 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_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(_sock->is_open(), ERR_ALREADY_IN_USE); 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; IP::Type ip_type = p_host.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6;
if (p_host.is_wildcard()) {
err = _sock->open(NetSocket::TYPE_TCP, ip_type); ip_type = IP::TYPE_ANY;
ERR_FAIL_COND_V(err != OK, FAILED); }
Error err = _sock->open(NetSocket::TYPE_TCP, ip_type);
if (err != OK) {
return err;
}
_sock->set_blocking_enabled(false); _sock->set_blocking_enabled(false);
return _sock->bind(p_host, p_port);
}
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).");
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); 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) { if (err == OK) {
status = STATUS_CONNECTED; status = STATUS_CONNECTED;
@ -300,10 +319,16 @@ IP_Address StreamPeerTCP::get_connected_host() const {
return peer_host; return peer_host;
} }
uint16_t StreamPeerTCP::get_connected_port() const { int StreamPeerTCP::get_connected_port() const {
return peer_port; 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) { Error StreamPeerTCP::_connect(const String &p_address, int p_port) {
IP_Address ip; IP_Address ip;
if (p_address.is_valid_ip_address()) { if (p_address.is_valid_ip_address()) {
@ -319,11 +344,13 @@ Error StreamPeerTCP::_connect(const String &p_address, int p_port) {
} }
void StreamPeerTCP::_bind_methods() { 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("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("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_status"), &StreamPeerTCP::get_status);
ClassDB::bind_method(D_METHOD("get_connected_host"), &StreamPeerTCP::get_connected_host); 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_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("disconnect_from_host"), &StreamPeerTCP::disconnect_from_host);
ClassDB::bind_method(D_METHOD("set_no_delay", "enabled"), &StreamPeerTCP::set_no_delay); ClassDB::bind_method(D_METHOD("set_no_delay", "enabled"), &StreamPeerTCP::set_no_delay);

View file

@ -65,10 +65,12 @@ protected:
public: public:
void accept_socket(Ref<NetSocket> p_sock, IP_Address p_host, uint16_t p_port); 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; bool is_connected_to_host() const;
IP_Address get_connected_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(); void disconnect_from_host();
int get_available_bytes() const override; int get_available_bytes() const override;

View file

@ -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("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_connection_available"), &TCP_Server::is_connection_available);
ClassDB::bind_method(D_METHOD("is_listening"), &TCP_Server::is_listening); 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("take_connection"), &TCP_Server::take_connection);
ClassDB::bind_method(D_METHOD("stop"), &TCP_Server::stop); ClassDB::bind_method(D_METHOD("stop"), &TCP_Server::stop);
} }
@ -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_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(_sock->is_open(), ERR_ALREADY_IN_USE); 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(!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; Error err;
IP::Type ip_type = IP::TYPE_ANY; IP::Type ip_type = IP::TYPE_ANY;
@ -74,6 +76,12 @@ Error TCP_Server::listen(uint16_t p_port, const IP_Address &p_bind_address) {
return OK; 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 { bool TCP_Server::is_listening() const {
ERR_FAIL_COND_V(!_sock.is_valid(), false); ERR_FAIL_COND_V(!_sock.is_valid(), false);

View file

@ -49,6 +49,7 @@ protected:
public: public:
Error listen(uint16_t p_port, const IP_Address &p_bind_address = IP_Address("*")); 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_listening() const;
bool is_connection_available() const; bool is_connection_available() const;
Ref<StreamPeerTCP> take_connection(); Ref<StreamPeerTCP> take_connection();

View file

@ -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("listen", "port", "bind_address"), &UDPServer::listen, DEFVAL("*"));
ClassDB::bind_method(D_METHOD("poll"), &UDPServer::poll); 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("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("is_listening"), &UDPServer::is_listening);
ClassDB::bind_method(D_METHOD("take_connection"), &UDPServer::take_connection); ClassDB::bind_method(D_METHOD("take_connection"), &UDPServer::take_connection);
ClassDB::bind_method(D_METHOD("stop"), &UDPServer::stop); ClassDB::bind_method(D_METHOD("stop"), &UDPServer::stop);
@ -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_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(_sock->is_open(), ERR_ALREADY_IN_USE); 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(!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; Error err;
IP::Type ip_type = IP::TYPE_ANY; IP::Type ip_type = IP::TYPE_ANY;
@ -112,11 +114,15 @@ Error UDPServer::listen(uint16_t p_port, const IP_Address &p_bind_address) {
stop(); stop();
return err; return err;
} }
bind_address = p_bind_address;
bind_port = p_port;
return OK; 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 { bool UDPServer::is_listening() const {
ERR_FAIL_COND_V(!_sock.is_valid(), false); ERR_FAIL_COND_V(!_sock.is_valid(), false);
@ -176,8 +182,6 @@ void UDPServer::stop() {
if (_sock.is_valid()) { if (_sock.is_valid()) {
_sock->close(); _sock->close();
} }
bind_port = 0;
bind_address = IP_Address();
List<Peer>::Element *E = peers.front(); List<Peer>::Element *E = peers.front();
while (E) { while (E) {
E->get().peer->disconnect_shared_socket(); E->get().peer->disconnect_shared_socket();

View file

@ -53,21 +53,18 @@ protected:
}; };
uint8_t recv_buffer[PACKET_BUFFER_SIZE]; uint8_t recv_buffer[PACKET_BUFFER_SIZE];
int bind_port = 0;
IP_Address bind_address;
List<Peer> peers; List<Peer> peers;
List<Peer> pending; List<Peer> pending;
int max_pending_connections = 16; int max_pending_connections = 16;
Ref<NetSocket> _sock; Ref<NetSocket> _sock;
static void _bind_methods(); static void _bind_methods();
public: public:
void remove_peer(IP_Address p_ip, int p_port); 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 listen(uint16_t p_port, const IP_Address &p_bind_address = IP_Address("*"));
Error poll(); Error poll();
int get_local_port() const;
bool is_listening() const; bool is_listening() const;
bool is_connection_available() const; bool is_connection_available() const;
void set_max_pending_connections(int p_max); void set_max_pending_connections(int p_max);

View file

@ -9,11 +9,27 @@
<tutorials> <tutorials>
</tutorials> </tutorials>
<methods> <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"> <method name="close">
<return type="void"> <return type="void">
</return> </return>
<description> <description>
Closes the UDP socket the [PacketPeerUDP] is currently listening on. Closes the [PacketPeerUDP]'s underlying UDP socket.
</description> </description>
</method> </method>
<method name="connect_to_host"> <method name="connect_to_host">
@ -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. [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> </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_ip" qualifiers="const"> <method name="get_packet_ip" qualifiers="const">
<return type="String"> <return type="String">
</return> </return>
@ -42,6 +65,13 @@
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]). 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> </description>
</method> </method>
<method name="is_bound" qualifiers="const">
<return type="bool">
</return>
<description>
Returns whether this [PacketPeerUDP] is bound to an address and can receive packets.
</description>
</method>
<method name="is_connected_to_host" qualifiers="const"> <method name="is_connected_to_host" qualifiers="const">
<return type="bool"> <return type="bool">
</return> </return>
@ -49,13 +79,6 @@
Returns [code]true[/code] if the UDP socket is open and has been connected to a remote address. See [method connect_to_host]. Returns [code]true[/code] if the UDP socket is open and has been connected to a remote address. See [method connect_to_host].
</description> </description>
</method> </method>
<method name="is_listening" qualifiers="const">
<return type="bool">
</return>
<description>
Returns whether this [PacketPeerUDP] is listening.
</description>
</method>
<method name="join_multicast_group"> <method name="join_multicast_group">
<return type="int" enum="Error"> <return type="int" enum="Error">
</return> </return>
@ -80,22 +103,6 @@
Removes the interface identified by [code]interface_name[/code] from the multicast group specified by [code]multicast_address[/code]. Removes the interface identified by [code]interface_name[/code] from the multicast group specified by [code]multicast_address[/code].
</description> </description>
</method> </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"> <method name="set_broadcast_enabled">
<return type="void"> <return type="void">
</return> </return>
@ -122,7 +129,7 @@
<return type="int" enum="Error"> <return type="int" enum="Error">
</return> </return>
<description> <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: [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] [codeblocks]
[gdscript] [gdscript]

View file

@ -9,6 +9,18 @@
<tutorials> <tutorials>
</tutorials> </tutorials>
<methods> <methods>
<method name="bind">
<return type="int" enum="Error">
</return>
<argument index="0" name="port" type="int">
</argument>
<argument index="1" name="host" type="String" default="&quot;*&quot;">
</argument>
<description>
Opens the TCP socket, and binds it to the specified local address.
This method is generally not needed, and only used to force the subsequent call to [method connect_to_host] to use the specified [code]host[/code] and [code]port[/code] as source address. This can be desired in some NAT punchthrough techniques, or when forcing the source network interface.
</description>
</method>
<method name="connect_to_host"> <method name="connect_to_host">
<return type="int" enum="Error"> <return type="int" enum="Error">
</return> </return>
@ -17,7 +29,7 @@
<argument index="1" name="port" type="int"> <argument index="1" name="port" type="int">
</argument> </argument>
<description> <description>
Connects to the specified [code]host:port[/code] pair. A hostname will be resolved if valid. Returns [constant OK] on success or [constant FAILED] on failure. Connects to the specified [code]host:port[/code] pair. A hostname will be resolved if valid. Returns [constant OK] on success.
</description> </description>
</method> </method>
<method name="disconnect_from_host"> <method name="disconnect_from_host">
@ -41,6 +53,13 @@
Returns the port of this peer. Returns the port of this peer.
</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_status"> <method name="get_status">
<return type="int" enum="StreamPeerTCP.Status"> <return type="int" enum="StreamPeerTCP.Status">
</return> </return>

View file

@ -9,6 +9,13 @@
<tutorials> <tutorials>
</tutorials> </tutorials>
<methods> <methods>
<method name="get_local_port" qualifiers="const">
<return type="int">
</return>
<description>
Returns the local port this server is listening to.
</description>
</method>
<method name="is_connection_available" qualifiers="const"> <method name="is_connection_available" qualifiers="const">
<return type="bool"> <return type="bool">
</return> </return>

View file

@ -123,6 +123,13 @@
<tutorials> <tutorials>
</tutorials> </tutorials>
<methods> <methods>
<method name="get_local_port" qualifiers="const">
<return type="int">
</return>
<description>
Returns the local port this server is listening to.
</description>
</method>
<method name="is_connection_available" qualifiers="const"> <method name="is_connection_available" qualifiers="const">
<return type="bool"> <return type="bool">
</return> </return>
@ -145,7 +152,7 @@
<argument index="1" name="bind_address" type="String" default="&quot;*&quot;"> <argument index="1" name="bind_address" type="String" default="&quot;*&quot;">
</argument> </argument>
<description> <description>
Starts the server by opening a UDP socket listening on the given port. You can optionally specify a [code]bind_address[/code] to only listen for packets sent to that address. See also [method PacketPeerUDP.listen]. Starts the server by opening a UDP socket listening on the given port. You can optionally specify a [code]bind_address[/code] to only listen for packets sent to that address. See also [method PacketPeerUDP.bind].
</description> </description>
</method> </method>
<method name="poll"> <method name="poll">

View file

@ -130,18 +130,23 @@ size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const
} }
} }
void NetSocketPosix::_set_ip_port(struct sockaddr_storage *p_addr, IP_Address &r_ip, uint16_t &r_port) { void NetSocketPosix::_set_ip_port(struct sockaddr_storage *p_addr, IP_Address *r_ip, uint16_t *r_port) {
if (p_addr->ss_family == AF_INET) { if (p_addr->ss_family == AF_INET) {
struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr; struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr;
r_ip.set_ipv4((uint8_t *)&(addr4->sin_addr.s_addr)); if (r_ip) {
r_ip->set_ipv4((uint8_t *)&(addr4->sin_addr.s_addr));
r_port = ntohs(addr4->sin_port); }
if (r_port) {
*r_port = ntohs(addr4->sin_port);
}
} else if (p_addr->ss_family == AF_INET6) { } else if (p_addr->ss_family == AF_INET6) {
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr; struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr;
r_ip.set_ipv6(addr6->sin6_addr.s6_addr); if (r_ip) {
r_ip->set_ipv6(addr6->sin6_addr.s6_addr);
r_port = ntohs(addr6->sin6_port); }
if (r_port) {
*r_port = ntohs(addr6->sin6_port);
}
}; };
} }
@ -186,13 +191,21 @@ NetSocketPosix::~NetSocketPosix() {
NetSocketPosix::NetError NetSocketPosix::_get_socket_error() const { NetSocketPosix::NetError NetSocketPosix::_get_socket_error() const {
#if defined(WINDOWS_ENABLED) #if defined(WINDOWS_ENABLED)
int err = WSAGetLastError(); int err = WSAGetLastError();
if (err == WSAEISCONN) {
if (err == WSAEISCONN)
return ERR_NET_IS_CONNECTED; return ERR_NET_IS_CONNECTED;
if (err == WSAEINPROGRESS || err == WSAEALREADY) }
if (err == WSAEINPROGRESS || err == WSAEALREADY) {
return ERR_NET_IN_PROGRESS; return ERR_NET_IN_PROGRESS;
if (err == WSAEWOULDBLOCK) }
if (err == WSAEWOULDBLOCK) {
return ERR_NET_WOULD_BLOCK; return ERR_NET_WOULD_BLOCK;
}
if (err == WSAEADDRINUSE || err == WSAEADDRNOTAVAIL) {
return ERR_NET_ADDRESS_INVALID_OR_UNAVAILABLE;
}
if (err == WSAEACCES) {
return ERR_NET_UNAUTHORIZED;
}
print_verbose("Socket error: " + itos(err)); print_verbose("Socket error: " + itos(err));
return ERR_NET_OTHER; return ERR_NET_OTHER;
#else #else
@ -205,6 +218,12 @@ NetSocketPosix::NetError NetSocketPosix::_get_socket_error() const {
if (errno == EAGAIN || errno == EWOULDBLOCK) { if (errno == EAGAIN || errno == EWOULDBLOCK) {
return ERR_NET_WOULD_BLOCK; return ERR_NET_WOULD_BLOCK;
} }
if (errno == EADDRINUSE || errno == EINVAL || errno == EADDRNOTAVAIL) {
return ERR_NET_ADDRESS_INVALID_OR_UNAVAILABLE;
}
if (errno == EACCES) {
return ERR_NET_UNAUTHORIZED;
}
print_verbose("Socket error: " + itos(errno)); print_verbose("Socket error: " + itos(errno));
return ERR_NET_OTHER; return ERR_NET_OTHER;
#endif #endif
@ -384,8 +403,8 @@ Error NetSocketPosix::bind(IP_Address p_addr, uint16_t p_port) {
size_t addr_size = _set_addr_storage(&addr, p_addr, p_port, _ip_type); size_t addr_size = _set_addr_storage(&addr, p_addr, p_port, _ip_type);
if (::bind(_sock, (struct sockaddr *)&addr, addr_size) != 0) { if (::bind(_sock, (struct sockaddr *)&addr, addr_size) != 0) {
_get_socket_error(); NetError err = _get_socket_error();
print_verbose("Failed to bind socket."); print_verbose("Failed to bind socket. Error: " + itos(err));
close(); close();
return ERR_UNAVAILABLE; return ERR_UNAVAILABLE;
} }
@ -716,6 +735,20 @@ int NetSocketPosix::get_available_bytes() const {
return len; return len;
} }
Error NetSocketPosix::get_socket_address(IP_Address *r_ip, uint16_t *r_port) const {
ERR_FAIL_COND_V(!is_open(), FAILED);
struct sockaddr_storage saddr;
socklen_t len = sizeof(saddr);
if (getsockname(_sock, (struct sockaddr *)&saddr, &len) != 0) {
_get_socket_error();
print_verbose("Error when reading local socket address.");
return FAILED;
}
_set_ip_port(&saddr, r_ip, r_port);
return OK;
}
Ref<NetSocket> NetSocketPosix::accept(IP_Address &r_ip, uint16_t &r_port) { Ref<NetSocket> NetSocketPosix::accept(IP_Address &r_ip, uint16_t &r_port) {
Ref<NetSocket> out; Ref<NetSocket> out;
ERR_FAIL_COND_V(!is_open(), out); ERR_FAIL_COND_V(!is_open(), out);
@ -729,7 +762,7 @@ Ref<NetSocket> NetSocketPosix::accept(IP_Address &r_ip, uint16_t &r_port) {
return out; return out;
} }
_set_ip_port(&their_addr, r_ip, r_port); _set_ip_port(&their_addr, &r_ip, &r_port);
NetSocketPosix *ns = memnew(NetSocketPosix); NetSocketPosix *ns = memnew(NetSocketPosix);
ns->_set_socket(fd, _ip_type, _is_stream); ns->_set_socket(fd, _ip_type, _is_stream);

View file

@ -54,7 +54,9 @@ private:
ERR_NET_WOULD_BLOCK, ERR_NET_WOULD_BLOCK,
ERR_NET_IS_CONNECTED, ERR_NET_IS_CONNECTED,
ERR_NET_IN_PROGRESS, ERR_NET_IN_PROGRESS,
ERR_NET_OTHER ERR_NET_ADDRESS_INVALID_OR_UNAVAILABLE,
ERR_NET_UNAUTHORIZED,
ERR_NET_OTHER,
}; };
NetError _get_socket_error() const; NetError _get_socket_error() const;
@ -70,7 +72,7 @@ protected:
public: public:
static void make_default(); static void make_default();
static void cleanup(); static void cleanup();
static void _set_ip_port(struct sockaddr_storage *p_addr, IP_Address &r_ip, uint16_t &r_port); static void _set_ip_port(struct sockaddr_storage *p_addr, IP_Address *r_ip, uint16_t *r_port);
static size_t _set_addr_storage(struct sockaddr_storage *p_addr, const IP_Address &p_ip, uint16_t p_port, IP::Type p_ip_type); static size_t _set_addr_storage(struct sockaddr_storage *p_addr, const IP_Address &p_ip, uint16_t p_port, IP::Type p_ip_type);
virtual Error open(Type p_sock_type, IP::Type &ip_type); virtual Error open(Type p_sock_type, IP::Type &ip_type);
@ -87,6 +89,7 @@ public:
virtual bool is_open() const; virtual bool is_open() const;
virtual int get_available_bytes() const; virtual int get_available_bytes() const;
virtual Error get_socket_address(IP_Address *r_ip, uint16_t *r_port) const;
virtual Error set_broadcasting_enabled(bool p_enabled); virtual Error set_broadcasting_enabled(bool p_enabled);
virtual void set_blocking_enabled(bool p_enabled); virtual void set_blocking_enabled(bool p_enabled);

View file

@ -172,7 +172,7 @@ public:
} }
Error bind(IP_Address p_ip, uint16_t p_port) { Error bind(IP_Address p_ip, uint16_t p_port) {
return udp->listen(p_port, p_ip); return udp->bind(p_port, p_ip);
} }
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) {