diff options
86 files changed, 1609 insertions, 2375 deletions
diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp index 8bffe3e88b..6b6856dcc8 100644 --- a/core/io/file_access_network.cpp +++ b/core/io/file_access_network.cpp @@ -227,7 +227,7 @@ FileAccessNetworkClient::FileAccessNetworkClient() { quit = false; singleton = this; last_id = 0; - client = Ref<StreamPeerTCP>(StreamPeerTCP::create_ref()); + client.instance(); sem = Semaphore::create(); lockcount = 0; } diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp index bfa2d3b389..c47ae05dc2 100644 --- a/core/io/http_client.cpp +++ b/core/io/http_client.cpp @@ -683,7 +683,7 @@ void HTTPClient::set_read_chunk_size(int p_size) { HTTPClient::HTTPClient() { - tcp_connection = StreamPeerTCP::create_ref(); + tcp_connection.instance(); resolving = IP::RESOLVER_INVALID_ID; status = STATUS_DISCONNECTED; conn_port = -1; diff --git a/drivers/unix/tcp_server_posix.h b/core/io/net_socket.cpp index c749314fb3..10bcf62eda 100644 --- a/drivers/unix/tcp_server_posix.h +++ b/core/io/net_socket.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* tcp_server_posix.h */ +/* net_socket.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,31 +28,15 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef TCP_SERVER_POSIX_H -#define TCP_SERVER_POSIX_H +#include "net_socket.h" -#ifdef UNIX_ENABLED -#include "core/io/tcp_server.h" +NetSocket *(*NetSocket::_create)() = NULL; -class TCPServerPosix : public TCP_Server { +NetSocket *NetSocket::create() { - int listen_sockfd; - IP::Type sock_type; + if (_create) + return _create(); - static TCP_Server *_create(); - -public: - virtual Error listen(uint16_t p_port, const IP_Address &p_bind_address = IP_Address("*")); - virtual bool is_connection_available() const; - virtual Ref<StreamPeerTCP> take_connection(); - - virtual void stop(); - - static void make_default(); - - TCPServerPosix(); - ~TCPServerPosix(); -}; - -#endif // TCP_SERVER_POSIX_H -#endif + ERR_PRINT("Unable to create network socket, platform not supported"); + return NULL; +} diff --git a/drivers/unix/stream_peer_tcp_posix.h b/core/io/net_socket.h index 05c48432db..0665bec9fd 100644 --- a/drivers/unix/stream_peer_tcp_posix.h +++ b/core/io/net_socket.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* stream_peer_tcp_posix.h */ +/* net_socket.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,63 +28,52 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef UNIX_ENABLED +#ifndef NET_SOCKET_H +#define NET_SOCKET_H -#ifndef STREAM_PEER_TCP_POSIX_H -#define STREAM_PEER_TCP_POSIX_H +#include "core/io/ip.h" +#include "core/reference.h" -#include "core/error_list.h" -#include "core/io/ip_address.h" -#include "core/io/stream_peer_tcp.h" - -class StreamPeerTCPPosix : public StreamPeerTCP { +class NetSocket : public Reference { protected: - mutable Status status; - - IP::Type sock_type; - int sockfd; - - Error _block(int p_sockfd, bool p_read, bool p_write) const; - - Error _poll_connection() const; - - IP_Address peer_host; - int peer_port; - - Error write(const uint8_t *p_data, int p_bytes, int &r_sent, bool p_block); - Error read(uint8_t *p_buffer, int p_bytes, int &r_received, bool p_block); - - static StreamPeerTCP *_create(); + static NetSocket *(*_create)(); public: - virtual Error connect_to_host(const IP_Address &p_host, uint16_t p_port); - - virtual Error put_data(const uint8_t *p_data, int p_bytes); - virtual Error put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent); - - virtual Error get_data(uint8_t *p_buffer, int p_bytes); - virtual Error get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received); - - virtual int get_available_bytes() const; - - void set_socket(int p_sockfd, IP_Address p_host, int p_port, IP::Type p_sock_type); - - virtual IP_Address get_connected_host() const; - virtual uint16_t get_connected_port() const; - - virtual bool is_connected_to_host() const; - virtual Status get_status() const; - virtual void disconnect_from_host(); - - virtual void set_no_delay(bool p_enabled); - - static void make_default(); - - StreamPeerTCPPosix(); - ~StreamPeerTCPPosix(); + static NetSocket *create(); + + enum PollType { + POLL_TYPE_IN, + POLL_TYPE_OUT, + POLL_TYPE_IN_OUT + }; + + enum Type { + TYPE_NONE, + TYPE_TCP, + TYPE_UDP, + }; + + virtual Error open(Type p_type, IP::Type &ip_type) = 0; + virtual void close() = 0; + virtual Error bind(IP_Address p_addr, uint16_t p_port) = 0; + virtual Error listen(int p_max_pending) = 0; + virtual Error connect_to_host(IP_Address p_addr, uint16_t p_port) = 0; + virtual Error poll(PollType p_type, int timeout) const = 0; + virtual Error recv(uint8_t *p_buffer, int p_len, int &r_read) = 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 send(const uint8_t *p_buffer, int p_len, int &r_sent) = 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 Ref<NetSocket> accept(IP_Address &r_ip, uint16_t &r_port) = 0; + + virtual bool is_open() const = 0; + virtual int get_available_bytes() const = 0; + + virtual void set_broadcasting_enabled(bool p_enabled) = 0; + virtual void set_blocking_enabled(bool p_enabled) = 0; + virtual void set_ipv6_only_enabled(bool p_enabled) = 0; + virtual void set_tcp_no_delay_enabled(bool p_enabled) = 0; + virtual void set_reuse_address_enabled(bool p_enabled) = 0; }; -#endif // TCP_CLIENT_POSIX_H - -#endif +#endif // NET_SOCKET_H diff --git a/core/io/packet_peer_udp.cpp b/core/io/packet_peer_udp.cpp index ef4fdd689c..d33ba6f855 100644 --- a/core/io/packet_peer_udp.cpp +++ b/core/io/packet_peer_udp.cpp @@ -32,8 +32,6 @@ #include "core/io/ip.h" -PacketPeerUDP *(*PacketPeerUDP::_create)() = NULL; - void PacketPeerUDP::set_blocking_mode(bool p_enable) { blocking = p_enable; @@ -59,6 +57,177 @@ Error PacketPeerUDP::_set_dest_address(const String &p_address, int p_port) { return OK; } +int PacketPeerUDP::get_available_packet_count() const { + + // TODO we should deprecate this, and expose poll instead! + Error err = const_cast<PacketPeerUDP *>(this)->_poll(); + if (err != OK) + return -1; + + return queue_count; +} + +Error PacketPeerUDP::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { + + Error err = _poll(); + if (err != OK) + return err; + if (queue_count == 0) + return ERR_UNAVAILABLE; + + uint32_t size = 0; + uint8_t ipv6[16]; + rb.read(ipv6, 16, true); + packet_ip.set_ipv6(ipv6); + rb.read((uint8_t *)&packet_port, 4, true); + rb.read((uint8_t *)&size, 4, true); + rb.read(packet_buffer, size, true); + --queue_count; + *r_buffer = packet_buffer; + r_buffer_size = size; + return OK; +} + +Error PacketPeerUDP::put_packet(const uint8_t *p_buffer, int p_buffer_size) { + + ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE); + ERR_FAIL_COND_V(!peer_addr.is_valid(), ERR_UNCONFIGURED); + + Error err; + int sent = -1; + + if (!_sock->is_open()) { + IP::Type ip_type = peer_addr.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6; + err = _sock->open(NetSocket::TYPE_UDP, ip_type); + ERR_FAIL_COND_V(err != OK, err); + _sock->set_blocking_enabled(false); + } + + do { + err = _sock->sendto(p_buffer, p_buffer_size, sent, peer_addr, peer_port); + if (err != OK) { + if (err != ERR_BUSY) + return FAILED; + else if (!blocking) + return ERR_BUSY; + // Keep trying to send full packet + continue; + } + return OK; + + } while (sent != p_buffer_size); + + return OK; +} + +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) { + + 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); + + Error err; + IP::Type ip_type = IP::TYPE_ANY; + + if (p_bind_address.is_valid()) + ip_type = p_bind_address.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6; + + err = _sock->open(NetSocket::TYPE_UDP, ip_type); + + if (err != OK) + return ERR_CANT_CREATE; + + _sock->set_blocking_enabled(false); + _sock->set_reuse_address_enabled(true); + err = _sock->bind(p_bind_address, p_port); + + if (err != OK) { + _sock->close(); + return err; + } + rb.resize(nearest_shift(p_recv_buffer_size)); + return OK; +} + +void PacketPeerUDP::close() { + + if (_sock.is_valid()) + _sock->close(); + rb.resize(16); + queue_count = 0; +} + +Error PacketPeerUDP::wait() { + + ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE); + return _sock->poll(NetSocket::POLL_TYPE_IN, -1); +} + +Error PacketPeerUDP::_poll() { + + ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE); + + if (!_sock->is_open()) { + return FAILED; + } + + Error err; + int read; + IP_Address ip; + uint16_t port; + + while (true) { + err = _sock->recvfrom(recv_buffer, sizeof(recv_buffer), read, ip, port); + + if (err != OK) { + if (err == ERR_BUSY) + break; + return FAILED; + } + + if (rb.space_left() < read + 24) { +#ifdef TOOLS_ENABLED + WARN_PRINTS("Buffer full, dropping packets!"); +#endif + continue; + } + + uint32_t port32 = port; + rb.write(ip.get_ipv6(), 16); + rb.write((uint8_t *)&port32, 4); + rb.write((uint8_t *)&read, 4); + rb.write(recv_buffer, read); + ++queue_count; + } + + return OK; +} +bool PacketPeerUDP::is_listening() const { + + return _sock.is_valid() && _sock->is_open(); +} + +IP_Address PacketPeerUDP::get_packet_address() const { + + return packet_ip; +} + +int PacketPeerUDP::get_packet_port() const { + + return packet_port; +} + +void PacketPeerUDP::set_dest_address(const IP_Address &p_address, int p_port) { + + 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)); @@ -66,26 +235,21 @@ void PacketPeerUDP::_bind_methods() { ClassDB::bind_method(D_METHOD("wait"), &PacketPeerUDP::wait); ClassDB::bind_method(D_METHOD("is_listening"), &PacketPeerUDP::is_listening); ClassDB::bind_method(D_METHOD("get_packet_ip"), &PacketPeerUDP::_get_packet_ip); - //ClassDB::bind_method(D_METHOD("get_packet_address"),&PacketPeerUDP::_get_packet_address); ClassDB::bind_method(D_METHOD("get_packet_port"), &PacketPeerUDP::get_packet_port); ClassDB::bind_method(D_METHOD("set_dest_address", "host", "port"), &PacketPeerUDP::_set_dest_address); } -Ref<PacketPeerUDP> PacketPeerUDP::create_ref() { - - if (!_create) - return Ref<PacketPeerUDP>(); - return Ref<PacketPeerUDP>(_create()); -} - -PacketPeerUDP *PacketPeerUDP::create() { +PacketPeerUDP::PacketPeerUDP() { - if (!_create) - return NULL; - return _create(); + _sock = Ref<NetSocket>(NetSocket::create()); + blocking = true; + packet_port = 0; + queue_count = 0; + peer_port = 0; + rb.resize(16); } -PacketPeerUDP::PacketPeerUDP() { +PacketPeerUDP::~PacketPeerUDP() { - blocking = true; + close(); } diff --git a/core/io/packet_peer_udp.h b/core/io/packet_peer_udp.h index 2ed53cef7f..4366b0eb82 100644 --- a/core/io/packet_peer_udp.h +++ b/core/io/packet_peer_udp.h @@ -32,36 +32,54 @@ #define PACKET_PEER_UDP_H #include "core/io/ip.h" +#include "core/io/net_socket.h" #include "core/io/packet_peer.h" class PacketPeerUDP : public PacketPeer { GDCLASS(PacketPeerUDP, PacketPeer); protected: + enum { + PACKET_BUFFER_SIZE = 65536 + }; + + RingBuffer<uint8_t> rb; + uint8_t recv_buffer[PACKET_BUFFER_SIZE]; + uint8_t packet_buffer[PACKET_BUFFER_SIZE]; + IP_Address packet_ip; + int packet_port; + int queue_count; + + IP_Address peer_addr; + int peer_port; bool blocking; + Ref<NetSocket> _sock; - static PacketPeerUDP *(*_create)(); static void _bind_methods(); String _get_packet_ip() const; Error _set_dest_address(const String &p_address, int p_port); + Error _poll(); public: void set_blocking_mode(bool p_enable); - virtual Error listen(int p_port, const IP_Address &p_bind_address = IP_Address("*"), int p_recv_buffer_size = 65536) = 0; - virtual void close() = 0; - virtual Error wait() = 0; - virtual bool is_listening() const = 0; - virtual IP_Address get_packet_address() const = 0; - virtual int get_packet_port() const = 0; - virtual void set_dest_address(const IP_Address &p_address, int p_port) = 0; + Error listen(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; + IP_Address get_packet_address() const; + int get_packet_port() const; + void set_dest_address(const IP_Address &p_address, int p_port); - static Ref<PacketPeerUDP> create_ref(); - static PacketPeerUDP *create(); + Error put_packet(const uint8_t *p_buffer, int p_buffer_size); + Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); + int get_available_packet_count() const; + int get_max_packet_size() const; PacketPeerUDP(); + ~PacketPeerUDP(); }; #endif // PACKET_PEER_UDP_H diff --git a/core/io/stream_peer_tcp.cpp b/core/io/stream_peer_tcp.cpp index 54ebb3ae0d..484e160f0e 100644 --- a/core/io/stream_peer_tcp.cpp +++ b/core/io/stream_peer_tcp.cpp @@ -30,7 +30,280 @@ #include "stream_peer_tcp.h" -StreamPeerTCP *(*StreamPeerTCP::_create)() = NULL; +Error StreamPeerTCP::_poll_connection() { + + ERR_FAIL_COND_V(status != STATUS_CONNECTING || !_sock.is_valid() || !_sock->is_open(), FAILED); + + Error err = _sock->connect_to_host(peer_host, peer_port); + + if (err == OK) { + status = STATUS_CONNECTED; + return OK; + } else if (err == ERR_BUSY) { + // Still trying to connect + return OK; + } + + status = STATUS_ERROR; + return ERR_CONNECTION_ERROR; +} + +void StreamPeerTCP::accept_socket(Ref<NetSocket> p_sock, IP_Address p_host, uint16_t p_port) { + + _sock = p_sock; + _sock->set_blocking_enabled(false); + + status = STATUS_CONNECTING; + + peer_host = p_host; + peer_port = p_port; +} + +Error StreamPeerTCP::connect_to_host(const IP_Address &p_host, uint16_t p_port) { + + 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); + + Error err; + IP::Type ip_type = p_host.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6; + + err = _sock->open(NetSocket::TYPE_TCP, ip_type); + ERR_FAIL_COND_V(err != OK, FAILED); + + _sock->set_blocking_enabled(false); + + err = _sock->connect_to_host(p_host, p_port); + + if (err != OK) { + if (err == ERR_BUSY) { + status = STATUS_CONNECTING; + } else { + ERR_PRINT("Connection to remote host failed!"); + disconnect_from_host(); + return FAILED; + } + } + + status = STATUS_CONNECTED; + peer_host = p_host; + peer_port = p_port; + + return OK; +} + +Error StreamPeerTCP::write(const uint8_t *p_data, int p_bytes, int &r_sent, bool p_block) { + + ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE); + + if (status == STATUS_NONE || status == STATUS_ERROR) { + + return FAILED; + } + + if (status != STATUS_CONNECTED) { + + if (_poll_connection() != OK) { + + return FAILED; + } + + if (status != STATUS_CONNECTED) { + r_sent = 0; + return OK; + } + } + + if (!_sock->is_open()) + return FAILED; + + Error err; + int data_to_send = p_bytes; + const uint8_t *offset = p_data; + int total_sent = 0; + + while (data_to_send) { + + int sent_amount = 0; + err = _sock->send(offset, data_to_send, sent_amount); + + if (err != OK) { + + if (err != ERR_BUSY) { + disconnect_from_host(); + return FAILED; + } + + if (!p_block) { + r_sent = total_sent; + return OK; + } + + // Block and wait for the socket to accept more data + err = _sock->poll(NetSocket::POLL_TYPE_OUT, -1); + if (err != OK) { + disconnect_from_host(); + return FAILED; + } + } else { + + data_to_send -= sent_amount; + offset += sent_amount; + total_sent += sent_amount; + } + } + + r_sent = total_sent; + + return OK; +} + +Error StreamPeerTCP::read(uint8_t *p_buffer, int p_bytes, int &r_received, bool p_block) { + + if (!is_connected_to_host()) { + + return FAILED; + }; + + if (status == STATUS_CONNECTING) { + + if (_poll_connection() != OK) { + + return FAILED; + }; + + if (status != STATUS_CONNECTED) { + r_received = 0; + return OK; + }; + }; + + Error err; + int to_read = p_bytes; + int total_read = 0; + r_received = 0; + + while (to_read) { + + int read = 0; + err = _sock->recv(p_buffer + total_read, to_read, read); + + if (err != OK) { + + if (err != ERR_BUSY) { + disconnect_from_host(); + return FAILED; + } + + if (!p_block) { + r_received = total_read; + return OK; + } + + err = _sock->poll(NetSocket::POLL_TYPE_IN, -1); + + if (err != OK) { + disconnect_from_host(); + return FAILED; + } + + } else if (read == 0) { + + _sock->close(); + status = STATUS_NONE; + peer_port = 0; + peer_host = IP_Address(); + r_received = total_read; + return ERR_FILE_EOF; + + } else { + + to_read -= read; + total_read += read; + } + } + + r_received = total_read; + + return OK; +} + +void StreamPeerTCP::set_no_delay(bool p_enabled) { + + ERR_FAIL_COND(!is_connected_to_host()); + _sock->set_tcp_no_delay_enabled(p_enabled); +} + +bool StreamPeerTCP::is_connected_to_host() const { + + if (status == STATUS_NONE || status == STATUS_ERROR) { + + return false; + } + + if (status != STATUS_CONNECTED) { + return true; + } + + return _sock.is_valid() && _sock->is_open(); +} + +StreamPeerTCP::Status StreamPeerTCP::get_status() { + + if (status == STATUS_CONNECTING) { + _poll_connection(); + } + + return status; +} + +void StreamPeerTCP::disconnect_from_host() { + + if (_sock.is_valid() && _sock->is_open()) + _sock->close(); + + status = STATUS_NONE; + peer_host = IP_Address(); + peer_port = 0; +} + +Error StreamPeerTCP::put_data(const uint8_t *p_data, int p_bytes) { + + int total; + return write(p_data, p_bytes, total, true); +} + +Error StreamPeerTCP::put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) { + + return write(p_data, p_bytes, r_sent, false); +} + +Error StreamPeerTCP::get_data(uint8_t *p_buffer, int p_bytes) { + + int total; + return read(p_buffer, p_bytes, total, true); +} + +Error StreamPeerTCP::get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) { + + return read(p_buffer, p_bytes, r_received, false); +} + +int StreamPeerTCP::get_available_bytes() const { + + ERR_FAIL_COND_V(!_sock.is_valid(), -1); + return _sock->get_available_bytes(); +} + +IP_Address StreamPeerTCP::get_connected_host() const { + + return peer_host; +} + +uint16_t StreamPeerTCP::get_connected_port() const { + + return peer_port; +} Error StreamPeerTCP::_connect(const String &p_address, int p_port) { @@ -62,23 +335,15 @@ void StreamPeerTCP::_bind_methods() { BIND_ENUM_CONSTANT(STATUS_ERROR); } -Ref<StreamPeerTCP> StreamPeerTCP::create_ref() { +StreamPeerTCP::StreamPeerTCP() { - if (!_create) - return Ref<StreamPeerTCP>(); - return Ref<StreamPeerTCP>(_create()); + _sock = Ref<NetSocket>(NetSocket::create()); + status = STATUS_NONE; + peer_host = IP_Address(); + peer_port = 0; } -StreamPeerTCP *StreamPeerTCP::create() { +StreamPeerTCP::~StreamPeerTCP() { - if (!_create) - return NULL; - return _create(); + disconnect_from_host(); } - -StreamPeerTCP::StreamPeerTCP() { -} - -StreamPeerTCP::~StreamPeerTCP(){ - -}; diff --git a/core/io/stream_peer_tcp.h b/core/io/stream_peer_tcp.h index dcda3b5bd7..de364915cd 100644 --- a/core/io/stream_peer_tcp.h +++ b/core/io/stream_peer_tcp.h @@ -33,6 +33,7 @@ #include "core/io/ip.h" #include "core/io/ip_address.h" +#include "core/io/net_socket.h" #include "core/io/stream_peer.h" class StreamPeerTCP : public StreamPeer { @@ -50,24 +51,37 @@ public: }; protected: - virtual Error _connect(const String &p_address, int p_port); - static StreamPeerTCP *(*_create)(); + Ref<NetSocket> _sock; + Status status; + IP_Address peer_host; + uint16_t peer_port; + + Error _connect(const String &p_address, int p_port); + Error _poll_connection(); + Error write(const uint8_t *p_data, int p_bytes, int &r_sent, bool p_block); + Error read(uint8_t *p_buffer, int p_bytes, int &r_received, bool p_block); + static void _bind_methods(); public: - virtual Error connect_to_host(const IP_Address &p_host, uint16_t p_port) = 0; + 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); + bool is_connected_to_host() const; + IP_Address get_connected_host() const; + uint16_t get_connected_port() const; + void disconnect_from_host(); - //read/write from streampeer + int get_available_bytes() const; + Status get_status(); - virtual bool is_connected_to_host() const = 0; - virtual Status get_status() const = 0; - virtual void disconnect_from_host() = 0; - virtual IP_Address get_connected_host() const = 0; - virtual uint16_t get_connected_port() const = 0; - virtual void set_no_delay(bool p_enabled) = 0; + void set_no_delay(bool p_enabled); - static Ref<StreamPeerTCP> create_ref(); - static StreamPeerTCP *create(); + // Read/Write from StreamPeer + Error put_data(const uint8_t *p_data, int p_bytes); + Error put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent); + Error get_data(uint8_t *p_buffer, int p_bytes); + Error get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received); StreamPeerTCP(); ~StreamPeerTCP(); diff --git a/core/io/tcp_server.cpp b/core/io/tcp_server.cpp index 5916d58390..b8194cb17f 100644 --- a/core/io/tcp_server.cpp +++ b/core/io/tcp_server.cpp @@ -30,29 +30,98 @@ #include "tcp_server.h" -TCP_Server *(*TCP_Server::_create)() = NULL; +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("take_connection"), &TCP_Server::take_connection); + ClassDB::bind_method(D_METHOD("stop"), &TCP_Server::stop); +} + +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); + + Error err; + IP::Type ip_type = IP::TYPE_ANY; + + // If the bind address is valid use its type as the socket type + if (p_bind_address.is_valid()) + ip_type = p_bind_address.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6; + + err = _sock->open(NetSocket::TYPE_TCP, ip_type); + + ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE); + + _sock->set_blocking_enabled(false); + _sock->set_reuse_address_enabled(true); + + err = _sock->bind(p_bind_address, p_port); + + if (err != OK) { + + _sock->close(); + return ERR_ALREADY_IN_USE; + } -Ref<TCP_Server> TCP_Server::create_ref() { + err = _sock->listen(MAX_PENDING_CONNECTIONS); - if (!_create) - return NULL; - return Ref<TCP_Server>(_create()); + if (err != OK) { + _sock->close(); + return FAILED; + } + return OK; } -TCP_Server *TCP_Server::create() { +bool TCP_Server::is_connection_available() const { - if (!_create) - return NULL; - return _create(); + ERR_FAIL_COND_V(!_sock.is_valid(), false); + + if (!_sock->is_open()) + return false; + + Error err = _sock->poll(NetSocket::POLL_TYPE_IN, 0); + if (err != OK) { + return false; + } + + return true; } -void TCP_Server::_bind_methods() { +Ref<StreamPeerTCP> TCP_Server::take_connection() { - 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("take_connection"), &TCP_Server::take_connection); - ClassDB::bind_method(D_METHOD("stop"), &TCP_Server::stop); + Ref<StreamPeerTCP> conn; + if (!is_connection_available()) { + return conn; + } + + Ref<NetSocket> ns; + IP_Address ip; + uint16_t port = 0; + ns = _sock->accept(ip, port); + if (!ns.is_valid()) + return conn; + + conn = Ref<StreamPeerTCP>(memnew(StreamPeerTCP)); + conn->accept_socket(ns, ip, port); + return conn; +} + +void TCP_Server::stop() { + + if (_sock.is_valid()) { + _sock->close(); + } } TCP_Server::TCP_Server() { + + _sock = Ref<NetSocket>(NetSocket::create()); +} + +TCP_Server::~TCP_Server() { + + stop(); } diff --git a/core/io/tcp_server.h b/core/io/tcp_server.h index 7353390bef..4c89197d9a 100644 --- a/core/io/tcp_server.h +++ b/core/io/tcp_server.h @@ -32,6 +32,7 @@ #define TCP_SERVER_H #include "core/io/ip.h" +#include "core/io/net_socket.h" #include "core/io/stream_peer.h" #include "core/io/stream_peer_tcp.h" @@ -40,22 +41,22 @@ class TCP_Server : public Reference { GDCLASS(TCP_Server, Reference); protected: - static TCP_Server *(*_create)(); + enum { + MAX_PENDING_CONNECTIONS = 8 + }; - //bind helper + Ref<NetSocket> _sock; static void _bind_methods(); public: - virtual Error listen(uint16_t p_port, const IP_Address &p_bind_address = IP_Address("*")) = 0; - virtual bool is_connection_available() const = 0; - virtual Ref<StreamPeerTCP> take_connection() = 0; + Error listen(uint16_t p_port, const IP_Address &p_bind_address = IP_Address("*")); + bool is_connection_available() const; + Ref<StreamPeerTCP> take_connection(); - virtual void stop() = 0; //stop listening - - static Ref<TCP_Server> create_ref(); - static TCP_Server *create(); + void stop(); // Stop listening TCP_Server(); + ~TCP_Server(); }; #endif // TCP_SERVER_H diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp index d93cad3f94..b0023b4c26 100644 --- a/core/register_core_types.cpp +++ b/core/register_core_types.cpp @@ -146,9 +146,9 @@ void register_core_types() { ClassDB::register_class<FuncRef>(); ClassDB::register_virtual_class<StreamPeer>(); ClassDB::register_class<StreamPeerBuffer>(); - ClassDB::register_custom_instance_class<StreamPeerTCP>(); - ClassDB::register_custom_instance_class<TCP_Server>(); - ClassDB::register_custom_instance_class<PacketPeerUDP>(); + ClassDB::register_class<StreamPeerTCP>(); + ClassDB::register_class<TCP_Server>(); + ClassDB::register_class<PacketPeerUDP>(); ClassDB::register_custom_instance_class<StreamPeerSSL>(); ClassDB::register_virtual_class<IP>(); ClassDB::register_virtual_class<PacketPeer>(); diff --git a/core/script_debugger_remote.cpp b/core/script_debugger_remote.cpp index ac684af6fe..0519807e63 100644 --- a/core/script_debugger_remote.cpp +++ b/core/script_debugger_remote.cpp @@ -1084,7 +1084,7 @@ ScriptDebuggerRemote::ScriptDebuggerRemote() : max_frame_functions(16), skip_profile_frame(false), reload_all_scripts(false), - tcp_client(StreamPeerTCP::create_ref()), + tcp_client(Ref<StreamPeerTCP>(memnew(StreamPeerTCP))), packet_peer_stream(Ref<PacketPeerStream>(memnew(PacketPeerStream))), last_perf_time(0), performance(Engine::get_singleton()->get_singleton_object("Performance")), diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 947729f6f6..1e43651d54 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -3098,40 +3098,6 @@ void RasterizerSceneGLES3::_copy_screen(bool p_invalidate_color, bool p_invalida glBindVertexArray(0); } -void RasterizerSceneGLES3::_copy_to_front_buffer(Environment *env) { - - //copy to front buffer - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); - - glDepthMask(GL_FALSE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - glDisable(GL_BLEND); - glDepthFunc(GL_LEQUAL); - glColorMask(1, 1, 1, 1); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->buffers.diffuse); - - storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, true); - - if (!env) { - //no environment, simply convert from linear to srgb - storage->shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB, true); - } else { - /* FIXME: Why are both statements equal? */ - storage->shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB, true); - } - - storage->shaders.copy.bind(); - - _copy_screen(); - - //turn off everything used - storage->shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB, false); - storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, false); -} - void RasterizerSceneGLES3::_copy_texture_to_front_buffer(GLuint p_texture) { //copy to front buffer diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index cf387a69bc..b4c4a0558f 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -837,7 +837,6 @@ public: void _setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, const CameraMatrix &p_camera_projection, RID p_reflection_atlas, Environment *p_env); void _copy_screen(bool p_invalidate_color = false, bool p_invalidate_depth = false); - void _copy_to_front_buffer(Environment *env); void _copy_texture_to_front_buffer(GLuint p_texture); //used for debug void _fill_render_list(InstanceBase **p_cull_result, int p_cull_count, bool p_depth_pass, bool p_shadow_pass); diff --git a/drivers/unix/net_socket_posix.cpp b/drivers/unix/net_socket_posix.cpp new file mode 100644 index 0000000000..ea19b6a700 --- /dev/null +++ b/drivers/unix/net_socket_posix.cpp @@ -0,0 +1,535 @@ +/*************************************************************************/ +/* net_socket_posix.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "net_socket_posix.h" + +#if defined(UNIX_ENABLED) + +#include <errno.h> +#include <netdb.h> +#include <poll.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <unistd.h> +#ifndef NO_FCNTL +#ifdef __HAIKU__ +#include <fcntl.h> +#else +#include <sys/fcntl.h> +#endif +#else +#include <sys/ioctl.h> +#endif +#include <netinet/in.h> + +#include <sys/socket.h> +#ifdef JAVASCRIPT_ENABLED +#include <arpa/inet.h> +#endif + +#include <netinet/tcp.h> + +#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED) +#define MSG_NOSIGNAL SO_NOSIGPIPE +#endif + +// Some custom defines to minimize ifdefs +#define SOCK_EMPTY -1 +#define SOCK_BUF(x) x +#define SOCK_CBUF(x) x +#define SOCK_IOCTL ioctl +#define SOCK_POLL ::poll +#define SOCK_CLOSE ::close + +/* Windows */ +#elif defined(WINDOWS_ENABLED) +#include <winsock2.h> +#include <ws2tcpip.h> +// Some custom defines to minimize ifdefs +#define SOCK_EMPTY INVALID_SOCKET +#define SOCK_BUF(x) (char *)(x) +#define SOCK_CBUF(x) (const char *)(x) +#define SOCK_IOCTL ioctlsocket +#define SOCK_POLL WSAPoll +#define SOCK_CLOSE closesocket + +// Windows doesn't have this flag +#ifndef MSG_NOSIGNAL +#define MSG_NOSIGNAL 0 +#endif + +#endif + +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) { + + memset(p_addr, 0, sizeof(struct sockaddr_storage)); + if (p_ip_type == IP::TYPE_IPV6 || p_ip_type == IP::TYPE_ANY) { // IPv6 socket + + // IPv6 only socket with IPv4 address + ERR_FAIL_COND_V(!p_ip.is_wildcard() && p_ip_type == IP::TYPE_IPV6 && p_ip.is_ipv4(), 0); + + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr; + addr6->sin6_family = AF_INET6; + addr6->sin6_port = htons(p_port); + if (p_ip.is_valid()) { + copymem(&addr6->sin6_addr.s6_addr, p_ip.get_ipv6(), 16); + } else { + addr6->sin6_addr = in6addr_any; + } + return sizeof(sockaddr_in6); + } else { // IPv4 socket + + // IPv4 socket with IPv6 address + ERR_FAIL_COND_V(!p_ip.is_ipv4(), 0); + + struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr; + addr4->sin_family = AF_INET; + addr4->sin_port = htons(p_port); // short, network byte order + + if (p_ip.is_valid()) { + copymem(&addr4->sin_addr.s_addr, p_ip.get_ipv4(), 4); + } else { + addr4->sin_addr.s_addr = INADDR_ANY; + } + + copymem(&addr4->sin_addr.s_addr, p_ip.get_ipv4(), 16); + return sizeof(sockaddr_in); + } +} + +static void _set_ip_port(IP_Address &r_ip, uint16_t &r_port, struct sockaddr_storage *p_addr) { + + if (p_addr->ss_family == AF_INET) { + + struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr; + r_ip.set_ipv4((uint8_t *)&(addr4->sin_addr.s_addr)); + + r_port = ntohs(addr4->sin_port); + + } else if (p_addr->ss_family == AF_INET6) { + + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr; + r_ip.set_ipv6(addr6->sin6_addr.s6_addr); + + r_port = ntohs(addr6->sin6_port); + }; +} + +NetSocket *NetSocketPosix::_create_func() { + return memnew(NetSocketPosix); +} + +void NetSocketPosix::make_default() { + _create = _create_func; +} + +NetSocketPosix::NetSocketPosix() { + _sock = SOCK_EMPTY; + _ip_type = IP::TYPE_NONE; + _is_stream = false; +} + +NetSocketPosix::~NetSocketPosix() { + close(); +} + +NetSocketPosix::NetError NetSocketPosix::_get_socket_error() { +#if defined(WINDOWS_ENABLED) + int err = WSAGetLastError(); + + if (err == WSAEISCONN) + return ERR_NET_IS_CONNECTED; + if (err == WSAEINPROGRESS || errno == WSAEALREADY) + return ERR_NET_IN_PROGRESS; + if (err == WSAEWOULDBLOCK) + return ERR_NET_WOULD_BLOCK; + return ERR_NET_OTHER; +#else + if (errno == EISCONN) + return ERR_NET_IS_CONNECTED; + if (errno == EINPROGRESS || errno == EALREADY) + return ERR_NET_IN_PROGRESS; + if (errno == EAGAIN || errno == EWOULDBLOCK) + return ERR_NET_WOULD_BLOCK; + return ERR_NET_OTHER; +#endif +} + +bool NetSocketPosix::_can_use_ip(const IP_Address p_ip, const bool p_for_bind) const { + + if (p_for_bind && !(p_ip.is_valid() || p_ip.is_wildcard())) { + return false; + } else if (!p_for_bind && !p_ip.is_valid()) { + return false; + } + // Check if socket support this IP type. + IP::Type type = p_ip.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6; + if (_ip_type != IP::TYPE_ANY && !p_ip.is_wildcard() && _ip_type != type) { + return false; + } + return true; +} + +void NetSocketPosix::_set_socket(SOCKET_TYPE p_sock, IP::Type p_ip_type, bool p_is_stream) { + _sock = p_sock; + _ip_type = p_ip_type; + _is_stream = p_is_stream; +} + +Error NetSocketPosix::open(Type p_sock_type, IP::Type &ip_type) { + ERR_FAIL_COND_V(is_open(), ERR_ALREADY_IN_USE); + ERR_FAIL_COND_V(ip_type > IP::TYPE_ANY || ip_type < IP::TYPE_NONE, ERR_INVALID_PARAMETER); + +#if defined(__OpenBSD__) + // OpenBSD does not support dual stacking, fallback to IPv4 only. + if (ip_type == IP::TYPE_ANY) + ip_type = IP::TYPE_IPV4; +#endif + + int family = ip_type == IP::TYPE_IPV4 ? AF_INET : AF_INET6; + int protocol = p_sock_type == TYPE_TCP ? IPPROTO_TCP : IPPROTO_UDP; + int type = p_sock_type == TYPE_TCP ? SOCK_STREAM : SOCK_DGRAM; + _sock = socket(family, type, protocol); + + if (_sock == SOCK_EMPTY && ip_type == IP::TYPE_ANY) { + // Careful here, changing the referenced parameter so the caller knows that we are using an IPv4 socket + // in place of a dual stack one, and further calls to _set_sock_addr will work as expected. + ip_type = IP::TYPE_IPV4; + family = AF_INET; + _sock = socket(family, type, protocol); + } + + ERR_FAIL_COND_V(_sock == SOCK_EMPTY, FAILED); + _ip_type = ip_type; + + if (family == AF_INET6) { + // Select IPv4 over IPv6 mapping + set_ipv6_only_enabled(ip_type != IP::TYPE_ANY); + } + + if (protocol == IPPROTO_UDP && ip_type != IP::TYPE_IPV6) { + // Enable broadcasting for UDP sockets if it's not IPv6 only (IPv6 has no broadcast option). + set_broadcasting_enabled(true); + } + + _is_stream = p_sock_type == TYPE_TCP; + return OK; +} + +void NetSocketPosix::close() { + + if (_sock != SOCK_EMPTY) + SOCK_CLOSE(_sock); + + _sock = SOCK_EMPTY; + _ip_type = IP::TYPE_NONE; + _is_stream = false; +} + +Error NetSocketPosix::bind(IP_Address p_addr, uint16_t p_port) { + + ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED); + ERR_FAIL_COND_V(!_can_use_ip(p_addr, true), ERR_INVALID_PARAMETER); + + sockaddr_storage addr; + size_t addr_size = _set_addr_storage(&addr, p_addr, p_port, _ip_type); + + if (::bind(_sock, (struct sockaddr *)&addr, addr_size) == SOCK_EMPTY) { + close(); + ERR_FAIL_V(ERR_UNAVAILABLE); + } + + return OK; +} + +Error NetSocketPosix::listen(int p_max_pending) { + ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED); + + if (::listen(_sock, p_max_pending) == SOCK_EMPTY) { + + close(); + ERR_FAIL_V(FAILED); + }; + + return OK; +} + +Error NetSocketPosix::connect_to_host(IP_Address p_host, uint16_t p_port) { + + ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED); + ERR_FAIL_COND_V(!_can_use_ip(p_host, false), ERR_INVALID_PARAMETER); + + struct sockaddr_storage addr; + size_t addr_size = _set_addr_storage(&addr, p_host, p_port, _ip_type); + + if (::connect(_sock, (struct sockaddr *)&addr, addr_size) == SOCK_EMPTY) { + + NetError err = _get_socket_error(); + + switch (err) { + // We are already connected + case ERR_NET_IS_CONNECTED: + return OK; + // Still waiting to connect, try again in a while + case ERR_NET_WOULD_BLOCK: + case ERR_NET_IN_PROGRESS: + return ERR_BUSY; + default: + ERR_PRINT("Connection to remote host failed!"); + close(); + return FAILED; + } + } + + return OK; +} + +Error NetSocketPosix::poll(PollType p_type, int timeout) const { + + ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED); + + struct pollfd pfd; + pfd.fd = _sock; + pfd.events = POLLIN; + pfd.revents = 0; + + switch (p_type) { + case POLL_TYPE_IN: + pfd.events = POLLIN; + break; + case POLL_TYPE_OUT: + pfd.events = POLLOUT; + break; + case POLL_TYPE_IN_OUT: + pfd.events = POLLOUT || POLLIN; + } + + int ret = SOCK_POLL(&pfd, 1, timeout); + + ERR_FAIL_COND_V(ret < 0, FAILED); + + if (ret == 0) + return ERR_BUSY; + + return OK; +} + +Error NetSocketPosix::recv(uint8_t *p_buffer, int p_len, int &r_read) { + ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED); + + r_read = ::recv(_sock, SOCK_BUF(p_buffer), p_len, 0); + + if (r_read < 0) { + NetError err = _get_socket_error(); + if (err == ERR_NET_WOULD_BLOCK) + return ERR_BUSY; + + return FAILED; + } + + return OK; +} + +Error NetSocketPosix::recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port) { + ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED); + + struct sockaddr_storage from; + socklen_t len = sizeof(struct sockaddr_storage); + memset(&from, 0, len); + + r_read = ::recvfrom(_sock, SOCK_BUF(p_buffer), p_len, 0, (struct sockaddr *)&from, &len); + + if (r_read < 0) { + NetError err = _get_socket_error(); + if (err == ERR_NET_WOULD_BLOCK) + return ERR_BUSY; + + return FAILED; + } + + if (from.ss_family == AF_INET) { + struct sockaddr_in *sin_from = (struct sockaddr_in *)&from; + r_ip.set_ipv4((uint8_t *)&sin_from->sin_addr); + r_port = ntohs(sin_from->sin_port); + } else if (from.ss_family == AF_INET6) { + struct sockaddr_in6 *s6_from = (struct sockaddr_in6 *)&from; + r_ip.set_ipv6((uint8_t *)&s6_from->sin6_addr); + r_port = ntohs(s6_from->sin6_port); + } else { + // Unsupported socket family, should never happen. + ERR_FAIL_V(FAILED); + } + + return OK; +} + +Error NetSocketPosix::send(const uint8_t *p_buffer, int p_len, int &r_sent) { + ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED); + + int flags = 0; + if (_is_stream) + flags = MSG_NOSIGNAL; + r_sent = ::send(_sock, SOCK_CBUF(p_buffer), p_len, flags); + + if (r_sent < 0) { + NetError err = _get_socket_error(); + if (err == ERR_NET_WOULD_BLOCK) + return ERR_BUSY; + + return FAILED; + } + + return OK; +} + +Error NetSocketPosix::sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) { + ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED); + + struct sockaddr_storage addr; + size_t addr_size = _set_addr_storage(&addr, p_ip, p_port, _ip_type); + r_sent = ::sendto(_sock, SOCK_CBUF(p_buffer), p_len, 0, (struct sockaddr *)&addr, addr_size); + + if (r_sent < 0) { + NetError err = _get_socket_error(); + if (err == ERR_NET_WOULD_BLOCK) + return ERR_BUSY; + + return FAILED; + } + + return OK; +} + +void NetSocketPosix::set_broadcasting_enabled(bool p_enabled) { + ERR_FAIL_COND(!is_open()); + // IPv6 has no broadcast support. + ERR_FAIL_COND(_ip_type == IP::TYPE_IPV6); + + int par = p_enabled ? 1 : 0; + if (setsockopt(_sock, SOL_SOCKET, SO_BROADCAST, SOCK_CBUF(&par), sizeof(int)) != 0) { + WARN_PRINT("Unable to change broadcast setting"); + } +} + +void NetSocketPosix::set_blocking_enabled(bool p_enabled) { + ERR_FAIL_COND(!is_open()); + + int ret = 0; +#if defined(WINDOWS_ENABLED) || defined(NO_FCNTL) + unsigned long par = p_enabled ? 0 : 1; + ret = SOCK_IOCTL(_sock, FIONBIO, &par); +#else + int opts = fcntl(_sock, F_GETFL); + if (p_enabled) + ret = fcntl(_sock, F_SETFL, opts & ~O_NONBLOCK); + else + ret = fcntl(_sock, F_SETFL, opts | O_NONBLOCK); +#endif + + if (ret != 0) + WARN_PRINT("Unable to change non-block mode"); +} + +void NetSocketPosix::set_ipv6_only_enabled(bool p_enabled) { + ERR_FAIL_COND(!is_open()); + // This option is only avaiable in IPv6 sockets. + ERR_FAIL_COND(_ip_type == IP::TYPE_IPV4); + + int par = p_enabled ? 1 : 0; + if (setsockopt(_sock, IPPROTO_IPV6, IPV6_V6ONLY, SOCK_CBUF(&par), sizeof(int)) != 0) { + WARN_PRINT("Unable to change IPv4 address mapping over IPv6 option"); + } +} + +void NetSocketPosix::set_tcp_no_delay_enabled(bool p_enabled) { + ERR_FAIL_COND(!is_open()); + ERR_FAIL_COND(_ip_type != TYPE_TCP); + + int par = p_enabled ? 1 : 0; + if (setsockopt(_sock, IPPROTO_TCP, TCP_NODELAY, SOCK_CBUF(&par), sizeof(int)) < 0) { + ERR_PRINT("Unable to set TCP no delay option"); + } +} + +void NetSocketPosix::set_reuse_address_enabled(bool p_enabled) { + ERR_FAIL_COND(!is_open()); + + int par = p_enabled ? 1 : 0; + if (setsockopt(_sock, SOL_SOCKET, SO_REUSEADDR, SOCK_CBUF(&par), sizeof(int)) < 0) { + WARN_PRINT("Unable to set socket REUSEADDR option!"); + } +} + +void NetSocketPosix::set_reuse_port_enabled(bool p_enabled) { +// Windows does not have this option, as it is always ON when setting REUSEADDR. +#ifndef WINDOWS_ENABLED + ERR_FAIL_COND(!is_open()); + + int par = p_enabled ? 1 : 0; + if (setsockopt(_sock, SOL_SOCKET, SO_REUSEPORT, SOCK_CBUF(&par), sizeof(int)) < 0) { + WARN_PRINT("Unable to set socket REUSEPORT option!"); + } +#endif +} + +bool NetSocketPosix::is_open() const { + return _sock != SOCK_EMPTY; +} + +int NetSocketPosix::get_available_bytes() const { + + ERR_FAIL_COND_V(_sock == SOCK_EMPTY, -1); + + unsigned long len; + int ret = SOCK_IOCTL(_sock, FIONREAD, &len); + ERR_FAIL_COND_V(ret == -1, 0); + return len; +} + +Ref<NetSocket> NetSocketPosix::accept(IP_Address &r_ip, uint16_t &r_port) { + + Ref<NetSocket> out; + ERR_FAIL_COND_V(!is_open(), out); + + struct sockaddr_storage their_addr; + socklen_t size = sizeof(their_addr); + SOCKET_TYPE fd = ::accept(_sock, (struct sockaddr *)&their_addr, &size); + ERR_FAIL_COND_V(fd == SOCK_EMPTY, out); + + _set_ip_port(r_ip, r_port, &their_addr); + + NetSocketPosix *ns = memnew(NetSocketPosix); + ns->_set_socket(fd, _ip_type, _is_stream); + ns->set_blocking_enabled(false); + return Ref<NetSocket>(ns); +} diff --git a/drivers/windows/stream_peer_tcp_winsock.h b/drivers/unix/net_socket_posix.h index 4a50e2f678..ee178136f3 100644 --- a/drivers/windows/stream_peer_tcp_winsock.h +++ b/drivers/unix/net_socket_posix.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* stream_peer_tcp_winsock.h */ +/* net_socket_posix.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,65 +28,70 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef WINDOWS_ENABLED +#ifndef NET_SOCKET_UNIX_H +#define NET_SOCKET_UNIX_H -#ifndef STREAM_PEER_TCP_WINSOCK_H -#define STREAM_PEER_TCP_WINSOCK_H +#include "core/io/net_socket.h" -#include "core/error_list.h" +#if defined(WINDOWS_ENABLED) +#include <winsock2.h> +#include <ws2tcpip.h> +#define SOCKET_TYPE SOCKET -#include "core/io/ip_address.h" -#include "core/io/stream_peer_tcp.h" +#else +#define SOCKET_TYPE int -class StreamPeerTCPWinsock : public StreamPeerTCP { - -protected: - mutable Status status; - IP::Type sock_type; +#endif - int sockfd; +class NetSocketPosix : public NetSocket { - Error _block(int p_sockfd, bool p_read, bool p_write) const; +private: + SOCKET_TYPE _sock; + IP::Type _ip_type; + bool _is_stream; - Error _poll_connection() const; + enum NetError { + ERR_NET_WOULD_BLOCK, + ERR_NET_IS_CONNECTED, + ERR_NET_IN_PROGRESS, + ERR_NET_OTHER + }; - IP_Address peer_host; - int peer_port; + NetError _get_socket_error(); + void _set_socket(SOCKET_TYPE p_sock, IP::Type p_ip_type, bool p_is_stream); - Error write(const uint8_t *p_data, int p_bytes, int &r_sent, bool p_block); - Error read(uint8_t *p_buffer, int p_bytes, int &r_received, bool p_block); +protected: + static NetSocket *_create_func(); - static StreamPeerTCP *_create(); + bool _can_use_ip(const IP_Address p_ip, const bool p_for_bind) const; public: - virtual Error connect_to_host(const IP_Address &p_host, uint16_t p_port); - - virtual Error put_data(const uint8_t *p_data, int p_bytes); - virtual Error put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent); - - virtual Error get_data(uint8_t *p_buffer, int p_bytes); - virtual Error get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received); + static void make_default(); + virtual Error open(Type p_sock_type, IP::Type &ip_type); + virtual void close(); + virtual Error bind(IP_Address p_addr, uint16_t p_port); + virtual Error listen(int p_max_pending); + virtual Error connect_to_host(IP_Address p_addr, uint16_t p_port); + virtual Error poll(PollType p_type, int timeout) const; + virtual Error recv(uint8_t *p_buffer, int p_len, int &r_read); + virtual Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port); + virtual Error send(const uint8_t *p_buffer, int p_len, int &r_sent); + virtual Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port); + virtual Ref<NetSocket> accept(IP_Address &r_ip, uint16_t &r_port); + + virtual bool is_open() const; virtual int get_available_bytes() const; - void set_socket(int p_sockfd, IP_Address p_host, int p_port, IP::Type p_sock_type); + virtual void set_broadcasting_enabled(bool p_enabled); + virtual void set_blocking_enabled(bool p_enabled); + virtual void set_ipv6_only_enabled(bool p_enabled); + virtual void set_tcp_no_delay_enabled(bool p_enabled); + virtual void set_reuse_address_enabled(bool p_enabled); + virtual void set_reuse_port_enabled(bool p_enabled); - virtual IP_Address get_connected_host() const; - virtual uint16_t get_connected_port() const; - - virtual bool is_connected_to_host() const; - virtual Status get_status() const; - virtual void disconnect_from_host(); - - static void make_default(); - static void cleanup(); - - virtual void set_no_delay(bool p_enabled); - - StreamPeerTCPWinsock(); - ~StreamPeerTCPWinsock(); + NetSocketPosix(); + ~NetSocketPosix(); }; -#endif // STREAM_PEER_TCP_WINSOCK_H - #endif diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index 6dba6923c3..1225d00aad 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -37,11 +37,9 @@ #include "drivers/unix/dir_access_unix.h" #include "drivers/unix/file_access_unix.h" #include "drivers/unix/mutex_posix.h" -#include "drivers/unix/packet_peer_udp_posix.h" +#include "drivers/unix/net_socket_posix.h" #include "drivers/unix/rw_lock_posix.h" #include "drivers/unix/semaphore_posix.h" -#include "drivers/unix/stream_peer_tcp_posix.h" -#include "drivers/unix/tcp_server_posix.h" #include "drivers/unix/thread_posix.h" #include "servers/visual_server.h" @@ -124,9 +122,7 @@ void OS_Unix::initialize_core() { DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_FILESYSTEM); #ifndef NO_NETWORK - TCPServerPosix::make_default(); - StreamPeerTCPPosix::make_default(); - PacketPeerUDPPosix::make_default(); + NetSocketPosix::make_default(); IP_Unix::make_default(); #endif diff --git a/drivers/unix/packet_peer_udp_posix.cpp b/drivers/unix/packet_peer_udp_posix.cpp deleted file mode 100644 index 1380c1d88b..0000000000 --- a/drivers/unix/packet_peer_udp_posix.cpp +++ /dev/null @@ -1,317 +0,0 @@ -/*************************************************************************/ -/* packet_peer_udp_posix.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "packet_peer_udp_posix.h" - -#ifdef UNIX_ENABLED - -#include <errno.h> -#include <netdb.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <unistd.h> - -#include <netinet/in.h> -#include <stdio.h> - -#ifndef NO_FCNTL -#ifdef __HAIKU__ -#include <fcntl.h> -#else -#include <sys/fcntl.h> -#endif -#else -#include <sys/ioctl.h> -#endif - -#ifdef JAVASCRIPT_ENABLED -#include <arpa/inet.h> -#endif - -#include "drivers/unix/socket_helpers.h" - -int PacketPeerUDPPosix::get_available_packet_count() const { - - Error err = const_cast<PacketPeerUDPPosix *>(this)->_poll(false); - if (err != OK) - return 0; - - return queue_count; -} - -Error PacketPeerUDPPosix::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { - - Error err = const_cast<PacketPeerUDPPosix *>(this)->_poll(false); - if (err != OK) - return err; - if (queue_count == 0) - return ERR_UNAVAILABLE; - - uint32_t size = 0; - uint8_t type = IP::TYPE_NONE; - rb.read(&type, 1, true); - if (type == IP::TYPE_IPV4) { - uint8_t ip[4]; - rb.read(ip, 4, true); - packet_ip.set_ipv4(ip); - } else { - uint8_t ipv6[16]; - rb.read(ipv6, 16, true); - packet_ip.set_ipv6(ipv6); - }; - rb.read((uint8_t *)&packet_port, 4, true); - rb.read((uint8_t *)&size, 4, true); - rb.read(packet_buffer, size, true); - --queue_count; - *r_buffer = packet_buffer; - r_buffer_size = size; - return OK; -} -Error PacketPeerUDPPosix::put_packet(const uint8_t *p_buffer, int p_buffer_size) { - - ERR_FAIL_COND_V(!peer_addr.is_valid(), ERR_UNCONFIGURED); - - if (sock_type == IP::TYPE_NONE) - sock_type = peer_addr.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6; - - int sock = _get_socket(); - ERR_FAIL_COND_V(sock == -1, FAILED); - struct sockaddr_storage addr; - size_t addr_size = _set_sockaddr(&addr, peer_addr, peer_port, sock_type); - - errno = 0; - int err; - - _set_sock_blocking(blocking); - - while ((err = sendto(sock, p_buffer, p_buffer_size, 0, (struct sockaddr *)&addr, addr_size)) != p_buffer_size) { - - if (errno != EAGAIN) { - return FAILED; - } else if (!blocking) { - return ERR_UNAVAILABLE; - } - } - - return OK; -} - -int PacketPeerUDPPosix::get_max_packet_size() const { - - return 512; // uhm maybe not -} - -Error PacketPeerUDPPosix::listen(int p_port, const IP_Address &p_bind_address, int p_recv_buffer_size) { - - ERR_FAIL_COND_V(sockfd != -1, ERR_ALREADY_IN_USE); - ERR_FAIL_COND_V(!p_bind_address.is_valid() && !p_bind_address.is_wildcard(), ERR_INVALID_PARAMETER); - -#ifdef __OpenBSD__ - sock_type = IP::TYPE_IPV4; // OpenBSD does not support dual stacking, fallback to IPv4 only. -#else - sock_type = IP::TYPE_ANY; -#endif - - if (p_bind_address.is_valid()) - sock_type = p_bind_address.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6; - - int sock = _get_socket(); - - if (sock == -1) - return ERR_CANT_CREATE; - - sockaddr_storage addr = { 0 }; - size_t addr_size = _set_listen_sockaddr(&addr, p_port, sock_type, IP_Address()); - - if (bind(sock, (struct sockaddr *)&addr, addr_size) == -1) { - close(); - return ERR_UNAVAILABLE; - } - rb.resize(nearest_shift(p_recv_buffer_size)); - return OK; -} - -void PacketPeerUDPPosix::close() { - - if (sockfd != -1) - ::close(sockfd); - sockfd = -1; - sock_type = IP::TYPE_NONE; - rb.resize(16); - queue_count = 0; -} - -Error PacketPeerUDPPosix::wait() { - - return _poll(true); -} - -Error PacketPeerUDPPosix::_poll(bool p_block) { - - if (sockfd == -1) { - return FAILED; - } - - _set_sock_blocking(p_block); - - struct sockaddr_storage from = { 0 }; - socklen_t len = sizeof(struct sockaddr_storage); - int ret; - while ((ret = recvfrom(sockfd, recv_buffer, MIN((int)sizeof(recv_buffer), MAX(rb.space_left() - 24, 0)), 0, (struct sockaddr *)&from, &len)) > 0) { - - uint32_t port = 0; - - if (from.ss_family == AF_INET) { - uint8_t type = (uint8_t)IP::TYPE_IPV4; - rb.write(&type, 1); - struct sockaddr_in *sin_from = (struct sockaddr_in *)&from; - rb.write((uint8_t *)&sin_from->sin_addr, 4); - port = ntohs(sin_from->sin_port); - - } else if (from.ss_family == AF_INET6) { - - uint8_t type = (uint8_t)IP::TYPE_IPV6; - rb.write(&type, 1); - - struct sockaddr_in6 *s6_from = (struct sockaddr_in6 *)&from; - rb.write((uint8_t *)&s6_from->sin6_addr, 16); - - port = ntohs(s6_from->sin6_port); - - } else { - // WARN_PRINT("Ignoring packet with unknown address family"); - uint8_t type = (uint8_t)IP::TYPE_NONE; - rb.write(&type, 1); - }; - - rb.write((uint8_t *)&port, 4); - rb.write((uint8_t *)&ret, 4); - rb.write(recv_buffer, ret); - - len = sizeof(struct sockaddr_storage); - ++queue_count; - if (p_block) - break; - }; - - // TODO: Should ECONNRESET be handled here? - if (ret == 0 || (ret == -1 && errno != EAGAIN)) { - close(); - return FAILED; - }; - - return OK; -} -bool PacketPeerUDPPosix::is_listening() const { - - return sockfd != -1; -} - -IP_Address PacketPeerUDPPosix::get_packet_address() const { - - return packet_ip; -} - -int PacketPeerUDPPosix::get_packet_port() const { - - return packet_port; -} - -int PacketPeerUDPPosix::_get_socket() { - - ERR_FAIL_COND_V(sock_type == IP::TYPE_NONE, -1); - - if (sockfd != -1) - return sockfd; - - sockfd = _socket_create(sock_type, SOCK_DGRAM, IPPROTO_UDP); - - if (sockfd != -1) - _set_sock_blocking(false); - - return sockfd; -} - -void PacketPeerUDPPosix::_set_sock_blocking(bool p_blocking) { - - if (sock_blocking == p_blocking) - return; - - sock_blocking = p_blocking; - -#ifndef NO_FCNTL - int opts = fcntl(sockfd, F_GETFL); - int ret = 0; - if (sock_blocking) - ret = fcntl(sockfd, F_SETFL, opts & ~O_NONBLOCK); - else - ret = fcntl(sockfd, F_SETFL, opts | O_NONBLOCK); - if (ret == -1) - perror("setting non-block mode"); -#else - int bval = sock_blocking ? 0 : 1; - if (ioctl(sockfd, FIONBIO, &bval) == -1) - perror("setting non-block mode"); -#endif -} - -void PacketPeerUDPPosix::set_dest_address(const IP_Address &p_address, int p_port) { - - peer_addr = p_address; - peer_port = p_port; -} - -PacketPeerUDP *PacketPeerUDPPosix::_create() { - - return memnew(PacketPeerUDPPosix); -}; - -void PacketPeerUDPPosix::make_default() { - - PacketPeerUDP::_create = PacketPeerUDPPosix::_create; -}; - -PacketPeerUDPPosix::PacketPeerUDPPosix() { - - blocking = true; - sock_blocking = true; - sockfd = -1; - packet_port = 0; - queue_count = 0; - peer_port = 0; - sock_type = IP::TYPE_NONE; - rb.resize(16); -} - -PacketPeerUDPPosix::~PacketPeerUDPPosix() { - - close(); -} -#endif diff --git a/drivers/unix/packet_peer_udp_posix.h b/drivers/unix/packet_peer_udp_posix.h deleted file mode 100644 index d366d88b77..0000000000 --- a/drivers/unix/packet_peer_udp_posix.h +++ /dev/null @@ -1,88 +0,0 @@ -/*************************************************************************/ -/* packet_peer_udp_posix.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef PACKET_PEER_UDP_POSIX_H -#define PACKET_PEER_UDP_POSIX_H - -#ifdef UNIX_ENABLED - -#include "core/io/packet_peer_udp.h" -#include "core/ring_buffer.h" - -class PacketPeerUDPPosix : public PacketPeerUDP { - - enum { - PACKET_BUFFER_SIZE = 65536 - }; - - RingBuffer<uint8_t> rb; - uint8_t recv_buffer[PACKET_BUFFER_SIZE]; - uint8_t packet_buffer[PACKET_BUFFER_SIZE]; - IP_Address packet_ip; - int packet_port; - int queue_count; - int sockfd; - bool sock_blocking; - IP::Type sock_type; - - IP_Address peer_addr; - int peer_port; - - _FORCE_INLINE_ int _get_socket(); - - static PacketPeerUDP *_create(); - void _set_sock_blocking(bool p_blocking); - virtual Error _poll(bool p_block); - -public: - virtual int get_available_packet_count() const; - virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); - virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size); - - virtual int get_max_packet_size() const; - - virtual Error listen(int p_port, const IP_Address &p_bind_address = IP_Address("*"), int p_recv_buffer_size = 65536); - virtual void close(); - virtual Error wait(); - virtual bool is_listening() const; - - virtual IP_Address get_packet_address() const; - virtual int get_packet_port() const; - - virtual void set_dest_address(const IP_Address &p_address, int p_port); - - static void make_default(); - - PacketPeerUDPPosix(); - ~PacketPeerUDPPosix(); -}; - -#endif // PACKET_PEER_UDP_POSIX_H -#endif diff --git a/drivers/unix/stream_peer_tcp_posix.cpp b/drivers/unix/stream_peer_tcp_posix.cpp deleted file mode 100644 index 44b9ef1d7c..0000000000 --- a/drivers/unix/stream_peer_tcp_posix.cpp +++ /dev/null @@ -1,411 +0,0 @@ -/*************************************************************************/ -/* stream_peer_tcp_posix.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifdef UNIX_ENABLED - -#include "stream_peer_tcp_posix.h" - -#include <errno.h> -#include <netdb.h> -#include <poll.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/ioctl.h> -#include <sys/types.h> -#include <unistd.h> -#ifndef NO_FCNTL -#ifdef __HAIKU__ -#include <fcntl.h> -#else -#include <sys/fcntl.h> -#endif -#else -#include <sys/ioctl.h> -#endif -#include <netinet/in.h> - -#include <sys/socket.h> -#ifdef JAVASCRIPT_ENABLED -#include <arpa/inet.h> -#endif - -#include <netinet/tcp.h> - -#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED) -#define MSG_NOSIGNAL SO_NOSIGPIPE -#endif - -#include "drivers/unix/socket_helpers.h" - -StreamPeerTCP *StreamPeerTCPPosix::_create() { - - return memnew(StreamPeerTCPPosix); -}; - -void StreamPeerTCPPosix::make_default() { - - StreamPeerTCP::_create = StreamPeerTCPPosix::_create; -}; - -Error StreamPeerTCPPosix::_block(int p_sockfd, bool p_read, bool p_write) const { - - struct pollfd pfd; - pfd.fd = p_sockfd; - pfd.events = 0; - if (p_read) - pfd.events |= POLLIN; - if (p_write) - pfd.events |= POLLOUT; - pfd.revents = 0; - - int ret = poll(&pfd, 1, -1); - return ret < 0 ? FAILED : OK; -}; - -Error StreamPeerTCPPosix::_poll_connection() const { - - ERR_FAIL_COND_V(status != STATUS_CONNECTING || sockfd == -1, FAILED); - - struct sockaddr_storage their_addr; - size_t addr_size = _set_sockaddr(&their_addr, peer_host, peer_port, sock_type); - - if (::connect(sockfd, (struct sockaddr *)&their_addr, addr_size) == -1) { - - if (errno == EISCONN) { - status = STATUS_CONNECTED; - return OK; - }; - - if (errno == EINPROGRESS || errno == EALREADY) { - return OK; - } - - status = STATUS_ERROR; - return ERR_CONNECTION_ERROR; - } else { - - status = STATUS_CONNECTED; - return OK; - }; - - return OK; -}; - -void StreamPeerTCPPosix::set_socket(int p_sockfd, IP_Address p_host, int p_port, IP::Type p_sock_type) { - - sock_type = p_sock_type; - sockfd = p_sockfd; -#ifndef NO_FCNTL - if (fcntl(sockfd, F_SETFL, O_NONBLOCK) < 0) { - WARN_PRINT("Error setting socket as non blocking"); - } -#else - int bval = 1; - if (ioctl(sockfd, FIONBIO, &bval) < 0) { - WARN_PRINT("Error setting socket as non blocking"); - } -#endif - status = STATUS_CONNECTING; - - peer_host = p_host; - peer_port = p_port; -}; - -Error StreamPeerTCPPosix::connect_to_host(const IP_Address &p_host, uint16_t p_port) { - - ERR_FAIL_COND_V(!p_host.is_valid(), ERR_INVALID_PARAMETER); - - sock_type = p_host.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6; - sockfd = _socket_create(sock_type, SOCK_STREAM, IPPROTO_TCP); - if (sockfd == -1) { - ERR_PRINT("Socket creation failed!"); - disconnect_from_host(); - //perror("socket"); - return FAILED; - }; - -#ifndef NO_FCNTL - if (fcntl(sockfd, F_SETFL, O_NONBLOCK) < 0) { - WARN_PRINT("Error setting socket as non blocking"); - } -#else - int bval = 1; - if (ioctl(sockfd, FIONBIO, &bval) < 0) { - WARN_PRINT("Error setting socket as non blocking"); - } -#endif - - struct sockaddr_storage their_addr; - size_t addr_size = _set_sockaddr(&their_addr, p_host, p_port, sock_type); - - errno = 0; - if (::connect(sockfd, (struct sockaddr *)&their_addr, addr_size) == -1 && errno != EINPROGRESS) { - - ERR_PRINT("Connection to remote host failed!"); - disconnect_from_host(); - return FAILED; - }; - - if (errno == EINPROGRESS) { - status = STATUS_CONNECTING; - } else { - status = STATUS_CONNECTED; - }; - - peer_host = p_host; - peer_port = p_port; - - return OK; -}; - -Error StreamPeerTCPPosix::write(const uint8_t *p_data, int p_bytes, int &r_sent, bool p_block) { - - if (status == STATUS_NONE || status == STATUS_ERROR) { - - return FAILED; - }; - - if (status != STATUS_CONNECTED) { - - if (_poll_connection() != OK) { - - return FAILED; - }; - - if (status != STATUS_CONNECTED) { - r_sent = 0; - return OK; - }; - }; - - int data_to_send = p_bytes; - const uint8_t *offset = p_data; - if (sockfd == -1) return FAILED; - errno = 0; - int total_sent = 0; - - while (data_to_send) { - - int sent_amount = send(sockfd, offset, data_to_send, MSG_NOSIGNAL); - //printf("Sent TCP data of %d bytes, errno %d\n", sent_amount, errno); - - if (sent_amount == -1) { - - if (errno != EAGAIN) { - - perror("Nothing sent"); - disconnect_from_host(); - ERR_PRINT("Server disconnected!\n"); - return FAILED; - }; - - if (!p_block) { - r_sent = total_sent; - return OK; - }; - - _block(sockfd, false, true); - } else { - - data_to_send -= sent_amount; - offset += sent_amount; - total_sent += sent_amount; - }; - } - - r_sent = total_sent; - - return OK; -}; - -Error StreamPeerTCPPosix::read(uint8_t *p_buffer, int p_bytes, int &r_received, bool p_block) { - - if (!is_connected_to_host()) { - - return FAILED; - }; - - if (status == STATUS_CONNECTING) { - - if (_poll_connection() != OK) { - - return FAILED; - }; - - if (status != STATUS_CONNECTED) { - r_received = 0; - return OK; - }; - }; - - int to_read = p_bytes; - int total_read = 0; - errno = 0; - - while (to_read) { - - int read = recv(sockfd, p_buffer + total_read, to_read, 0); - - if (read == -1) { - - if (errno != EAGAIN) { - - perror("Nothing read"); - disconnect_from_host(); - ERR_PRINT("Server disconnected!\n"); - return FAILED; - }; - - if (!p_block) { - - r_received = total_read; - return OK; - }; - _block(sockfd, true, false); - - } else if (read == 0) { - - sockfd = -1; - status = STATUS_NONE; - peer_port = 0; - peer_host = IP_Address(); - r_received = total_read; - return ERR_FILE_EOF; - - } else { - - to_read -= read; - total_read += read; - }; - }; - - r_received = total_read; - - return OK; -}; - -void StreamPeerTCPPosix::set_no_delay(bool p_enabled) { - - ERR_FAIL_COND(!is_connected_to_host()); - int flag = p_enabled ? 1 : 0; - if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int)) < 0) { - ERR_PRINT("Unable to set TCP no delay option"); - } -} - -bool StreamPeerTCPPosix::is_connected_to_host() const { - - if (status == STATUS_NONE || status == STATUS_ERROR) { - - return false; - }; - if (status != STATUS_CONNECTED) { - return true; - }; - - return (sockfd != -1); -}; - -StreamPeerTCP::Status StreamPeerTCPPosix::get_status() const { - - if (status == STATUS_CONNECTING) { - _poll_connection(); - }; - - return status; -}; - -void StreamPeerTCPPosix::disconnect_from_host() { - - if (sockfd != -1) - close(sockfd); - - sock_type = IP::TYPE_NONE; - sockfd = -1; - - status = STATUS_NONE; - peer_port = 0; - peer_host = IP_Address(); -}; - -Error StreamPeerTCPPosix::put_data(const uint8_t *p_data, int p_bytes) { - - int total; - return write(p_data, p_bytes, total, true); -}; - -Error StreamPeerTCPPosix::put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) { - - return write(p_data, p_bytes, r_sent, false); -}; - -Error StreamPeerTCPPosix::get_data(uint8_t *p_buffer, int p_bytes) { - - int total; - return read(p_buffer, p_bytes, total, true); -}; - -Error StreamPeerTCPPosix::get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) { - - return read(p_buffer, p_bytes, r_received, false); -}; - -int StreamPeerTCPPosix::get_available_bytes() const { - - unsigned long len; - int ret = ioctl(sockfd, FIONREAD, &len); - ERR_FAIL_COND_V(ret == -1, 0) - return len; -} -IP_Address StreamPeerTCPPosix::get_connected_host() const { - - return peer_host; -}; - -uint16_t StreamPeerTCPPosix::get_connected_port() const { - - return peer_port; -}; - -StreamPeerTCPPosix::StreamPeerTCPPosix() { - - sock_type = IP::TYPE_NONE; - sockfd = -1; - status = STATUS_NONE; - peer_port = 0; -}; - -StreamPeerTCPPosix::~StreamPeerTCPPosix() { - - disconnect_from_host(); -}; - -#endif diff --git a/drivers/unix/tcp_server_posix.cpp b/drivers/unix/tcp_server_posix.cpp deleted file mode 100644 index 67ab981f46..0000000000 --- a/drivers/unix/tcp_server_posix.cpp +++ /dev/null @@ -1,207 +0,0 @@ -/*************************************************************************/ -/* tcp_server_posix.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "tcp_server_posix.h" -#include "stream_peer_tcp_posix.h" - -#ifdef UNIX_ENABLED - -#include <poll.h> - -#include <errno.h> -#include <netdb.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/types.h> -#include <unistd.h> -#ifndef NO_FCNTL -#ifdef __HAIKU__ -#include <fcntl.h> -#else -#include <sys/fcntl.h> -#endif -#else -#include <sys/ioctl.h> -#endif -#ifdef JAVASCRIPT_ENABLED -#include <arpa/inet.h> -#endif -#include <assert.h> -#include <netinet/in.h> -#include <sys/socket.h> - -#include "drivers/unix/socket_helpers.h" - -TCP_Server *TCPServerPosix::_create() { - - return memnew(TCPServerPosix); -}; - -void TCPServerPosix::make_default() { - - TCP_Server::_create = TCPServerPosix::_create; -}; - -Error TCPServerPosix::listen(uint16_t p_port, const IP_Address &p_bind_address) { - - ERR_FAIL_COND_V(listen_sockfd != -1, ERR_ALREADY_IN_USE); - ERR_FAIL_COND_V(!p_bind_address.is_valid() && !p_bind_address.is_wildcard(), ERR_INVALID_PARAMETER); - - int sockfd; -#ifdef __OpenBSD__ - sock_type = IP::TYPE_IPV4; // OpenBSD does not support dual stacking, fallback to IPv4 only. -#else - sock_type = IP::TYPE_ANY; -#endif - - // If the bind address is valid use its type as the socket type - if (p_bind_address.is_valid()) - sock_type = p_bind_address.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6; - - sockfd = _socket_create(sock_type, SOCK_STREAM, IPPROTO_TCP); - - ERR_FAIL_COND_V(sockfd == -1, FAILED); - -#ifndef NO_FCNTL - if (fcntl(sockfd, F_SETFL, O_NONBLOCK) < 0) { - WARN_PRINT("Error setting socket as non blocking"); - } -#else - int bval = 1; - if (ioctl(sockfd, FIONBIO, &bval) < 0) { - WARN_PRINT("Error setting socket as non blocking"); - } -#endif - - int reuse = 1; - if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0) { - WARN_PRINT("REUSEADDR failed!") - } - - struct sockaddr_storage addr; - size_t addr_size = _set_listen_sockaddr(&addr, p_port, sock_type, p_bind_address); - - if (bind(sockfd, (struct sockaddr *)&addr, addr_size) != -1) { - - if (::listen(sockfd, 1) == -1) { - - close(sockfd); - ERR_FAIL_V(FAILED); - }; - } else { - close(sockfd); - return ERR_ALREADY_IN_USE; - }; - - if (listen_sockfd != -1) { - stop(); - }; - - listen_sockfd = sockfd; - - return OK; -}; - -bool TCPServerPosix::is_connection_available() const { - - if (listen_sockfd == -1) { - return false; - }; - - struct pollfd pfd; - pfd.fd = listen_sockfd; - pfd.events = POLLIN; - pfd.revents = 0; - - int ret = poll(&pfd, 1, 0); - ERR_FAIL_COND_V(ret < 0, FAILED); - - if (ret && (pfd.revents & POLLIN)) { - return true; - }; - - return false; -}; - -Ref<StreamPeerTCP> TCPServerPosix::take_connection() { - - if (!is_connection_available()) { - return Ref<StreamPeerTCP>(); - }; - - struct sockaddr_storage their_addr; - socklen_t size = sizeof(their_addr); - int fd = accept(listen_sockfd, (struct sockaddr *)&their_addr, &size); - ERR_FAIL_COND_V(fd == -1, Ref<StreamPeerTCP>()); -#ifndef NO_FCNTL - if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { - WARN_PRINT("Error setting socket as non blocking"); - } -#else - int bval = 1; - if (ioctl(fd, FIONBIO, &bval) < 0) { - WARN_PRINT("Error setting socket as non blocking"); - } -#endif - - Ref<StreamPeerTCPPosix> conn = memnew(StreamPeerTCPPosix); - IP_Address ip; - - int port = 0; - _set_ip_addr_port(ip, port, &their_addr); - - conn->set_socket(fd, ip, port, sock_type); - - return conn; -}; - -void TCPServerPosix::stop() { - - if (listen_sockfd != -1) { - int ret = close(listen_sockfd); - ERR_FAIL_COND(ret != 0); - }; - - listen_sockfd = -1; - sock_type = IP::TYPE_NONE; -}; - -TCPServerPosix::TCPServerPosix() { - - listen_sockfd = -1; - sock_type = IP::TYPE_NONE; -}; - -TCPServerPosix::~TCPServerPosix() { - - stop(); -}; -#endif diff --git a/drivers/windows/packet_peer_udp_winsock.cpp b/drivers/windows/packet_peer_udp_winsock.cpp deleted file mode 100644 index 66221774b2..0000000000 --- a/drivers/windows/packet_peer_udp_winsock.cpp +++ /dev/null @@ -1,299 +0,0 @@ -/*************************************************************************/ -/* packet_peer_udp_winsock.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifdef WINDOWS_ENABLED - -#include "packet_peer_udp_winsock.h" - -#include <winsock2.h> -#include <ws2tcpip.h> - -// Must be included after Windows headers or hell breaks loose -#include "drivers/unix/socket_helpers.h" - -int PacketPeerUDPWinsock::get_available_packet_count() const { - - Error err = const_cast<PacketPeerUDPWinsock *>(this)->_poll(false); - if (err != OK) - return 0; - - return queue_count; -} - -Error PacketPeerUDPWinsock::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { - - Error err = const_cast<PacketPeerUDPWinsock *>(this)->_poll(false); - if (err != OK) - return err; - if (queue_count == 0) - return ERR_UNAVAILABLE; - - uint32_t size; - uint8_t type; - rb.read(&type, 1, true); - if (type == IP::TYPE_IPV4) { - uint8_t ip[4]; - rb.read(ip, 4, true); - packet_ip.set_ipv4(ip); - } else { - uint8_t ip[16]; - rb.read(ip, 16, true); - packet_ip.set_ipv6(ip); - }; - rb.read((uint8_t *)&packet_port, 4, true); - rb.read((uint8_t *)&size, 4, true); - rb.read(packet_buffer, size, true); - --queue_count; - *r_buffer = packet_buffer; - r_buffer_size = size; - return OK; -} -Error PacketPeerUDPWinsock::put_packet(const uint8_t *p_buffer, int p_buffer_size) { - - ERR_FAIL_COND_V(!peer_addr.is_valid(), ERR_UNCONFIGURED); - - if (sock_type == IP::TYPE_NONE) - sock_type = peer_addr.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6; - - int sock = _get_socket(); - ERR_FAIL_COND_V(sock == -1, FAILED); - struct sockaddr_storage addr; - size_t addr_size = _set_sockaddr(&addr, peer_addr, peer_port, sock_type); - - _set_sock_blocking(blocking); - - errno = 0; - int err; - while ((err = sendto(sock, (const char *)p_buffer, p_buffer_size, 0, (struct sockaddr *)&addr, addr_size)) != p_buffer_size) { - - if (WSAGetLastError() != WSAEWOULDBLOCK) { - return FAILED; - } else if (!blocking) { - return ERR_UNAVAILABLE; - } - } - - return OK; -} - -int PacketPeerUDPWinsock::get_max_packet_size() const { - - return 512; // uhm maybe not -} - -void PacketPeerUDPWinsock::_set_sock_blocking(bool p_blocking) { - - if (sock_blocking == p_blocking) - return; - - sock_blocking = p_blocking; - unsigned long par = sock_blocking ? 0 : 1; - if (ioctlsocket(sockfd, FIONBIO, &par)) { - perror("setting non-block mode"); - //close(); - //return -1; - }; -} - -Error PacketPeerUDPWinsock::listen(int p_port, const IP_Address &p_bind_address, int p_recv_buffer_size) { - - ERR_FAIL_COND_V(sockfd != -1, ERR_ALREADY_IN_USE); - ERR_FAIL_COND_V(!p_bind_address.is_valid() && !p_bind_address.is_wildcard(), ERR_INVALID_PARAMETER); - - sock_type = IP::TYPE_ANY; - - if (p_bind_address.is_valid()) - sock_type = p_bind_address.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6; - - int sock = _get_socket(); - if (sock == -1) - return ERR_CANT_CREATE; - - struct sockaddr_storage addr = { 0 }; - size_t addr_size = _set_listen_sockaddr(&addr, p_port, sock_type, IP_Address()); - - if (bind(sock, (struct sockaddr *)&addr, addr_size) == -1) { - close(); - return ERR_UNAVAILABLE; - } - - printf("UDP Connection listening on port %i\n", p_port); - rb.resize(nearest_shift(p_recv_buffer_size)); - return OK; -} - -void PacketPeerUDPWinsock::close() { - - if (sockfd != -1) - ::closesocket(sockfd); - sockfd = -1; - sock_type = IP::TYPE_NONE; - rb.resize(16); - queue_count = 0; -} - -Error PacketPeerUDPWinsock::wait() { - - return _poll(true); -} -Error PacketPeerUDPWinsock::_poll(bool p_wait) { - - if (sockfd == -1) { - return FAILED; - } - - _set_sock_blocking(p_wait); - - struct sockaddr_storage from = { 0 }; - int len = sizeof(struct sockaddr_storage); - int ret; - while ((ret = recvfrom(sockfd, (char *)recv_buffer, MIN((int)sizeof(recv_buffer), MAX(rb.space_left() - 24, 0)), 0, (struct sockaddr *)&from, &len)) > 0) { - - uint32_t port = 0; - - if (from.ss_family == AF_INET) { - uint8_t type = (uint8_t)IP::TYPE_IPV4; - rb.write(&type, 1); - struct sockaddr_in *sin_from = (struct sockaddr_in *)&from; - rb.write((uint8_t *)&sin_from->sin_addr, 4); - port = ntohs(sin_from->sin_port); - - } else if (from.ss_family == AF_INET6) { - - uint8_t type = (uint8_t)IP::TYPE_IPV6; - rb.write(&type, 1); - - struct sockaddr_in6 *s6_from = (struct sockaddr_in6 *)&from; - rb.write((uint8_t *)&s6_from->sin6_addr, 16); - - port = ntohs(s6_from->sin6_port); - - } else { - // WARN_PRINT("Ignoring packet with unknown address family"); - uint8_t type = (uint8_t)IP::TYPE_NONE; - rb.write(&type, 1); - }; - - rb.write((uint8_t *)&port, 4); - rb.write((uint8_t *)&ret, 4); - rb.write(recv_buffer, ret); - - len = sizeof(struct sockaddr_storage); - ++queue_count; - if (p_wait) - break; - }; - - if (ret == SOCKET_ERROR) { - int error = WSAGetLastError(); - - if (error == WSAEWOULDBLOCK) { - // Expected when doing non-blocking sockets, retry later. - } else if (error == WSAECONNRESET) { - // If the remote target does not accept messages, this error may occur, but is harmless. - // Once the remote target gets available, this message will disappear for new messages. - } else { - close(); - return FAILED; - } - } - - if (ret == 0) { - close(); - return FAILED; - }; - - return OK; -} - -bool PacketPeerUDPWinsock::is_listening() const { - - return sockfd != -1; -} - -IP_Address PacketPeerUDPWinsock::get_packet_address() const { - - return packet_ip; -} - -int PacketPeerUDPWinsock::get_packet_port() const { - - return packet_port; -} - -int PacketPeerUDPWinsock::_get_socket() { - - ERR_FAIL_COND_V(sock_type == IP::TYPE_NONE, -1); - - if (sockfd != -1) - return sockfd; - - sockfd = _socket_create(sock_type, SOCK_DGRAM, IPPROTO_UDP); - - if (sockfd != -1) - _set_sock_blocking(false); - - return sockfd; -} - -void PacketPeerUDPWinsock::set_dest_address(const IP_Address &p_address, int p_port) { - - peer_addr = p_address; - peer_port = p_port; -} - -void PacketPeerUDPWinsock::make_default() { - - PacketPeerUDP::_create = PacketPeerUDPWinsock::_create; -}; - -PacketPeerUDP *PacketPeerUDPWinsock::_create() { - - return memnew(PacketPeerUDPWinsock); -}; - -PacketPeerUDPWinsock::PacketPeerUDPWinsock() { - - blocking = true; - sock_blocking = true; - sockfd = -1; - packet_port = 0; - queue_count = 0; - peer_port = 0; - sock_type = IP::TYPE_NONE; - rb.resize(16); -} - -PacketPeerUDPWinsock::~PacketPeerUDPWinsock() { - - close(); -} - -#endif diff --git a/drivers/windows/packet_peer_udp_winsock.h b/drivers/windows/packet_peer_udp_winsock.h deleted file mode 100644 index 91087af7cb..0000000000 --- a/drivers/windows/packet_peer_udp_winsock.h +++ /dev/null @@ -1,89 +0,0 @@ -/*************************************************************************/ -/* packet_peer_udp_winsock.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifdef WINDOWS_ENABLED - -#ifndef PACKET_PEER_UDP_WINSOCK_H -#define PACKET_PEER_UDP_WINSOCK_H - -#include "core/io/packet_peer_udp.h" -#include "core/ring_buffer.h" - -class PacketPeerUDPWinsock : public PacketPeerUDP { - - enum { - PACKET_BUFFER_SIZE = 65536 - }; - - RingBuffer<uint8_t> rb; - uint8_t recv_buffer[PACKET_BUFFER_SIZE]; - uint8_t packet_buffer[PACKET_BUFFER_SIZE]; - IP_Address packet_ip; - int packet_port; - int queue_count; - int sockfd; - bool sock_blocking; - IP::Type sock_type; - - IP_Address peer_addr; - int peer_port; - - _FORCE_INLINE_ int _get_socket(); - - static PacketPeerUDP *_create(); - - void _set_sock_blocking(bool p_blocking); - - Error _poll(bool p_wait); - -public: - virtual int get_available_packet_count() const; - virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); - virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size); - - virtual int get_max_packet_size() const; - - virtual Error listen(int p_port, const IP_Address &p_bind_address = IP_Address("*"), int p_recv_buffer_size = 65536); - virtual void close(); - virtual Error wait(); - virtual bool is_listening() const; - - virtual IP_Address get_packet_address() const; - virtual int get_packet_port() const; - - virtual void set_dest_address(const IP_Address &p_address, int p_port); - - static void make_default(); - PacketPeerUDPWinsock(); - ~PacketPeerUDPWinsock(); -}; -#endif // PACKET_PEER_UDP_WINSOCK_H - -#endif diff --git a/drivers/windows/stream_peer_tcp_winsock.cpp b/drivers/windows/stream_peer_tcp_winsock.cpp deleted file mode 100644 index 19c937170b..0000000000 --- a/drivers/windows/stream_peer_tcp_winsock.cpp +++ /dev/null @@ -1,375 +0,0 @@ -/*************************************************************************/ -/* stream_peer_tcp_winsock.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifdef WINDOWS_ENABLED - -#include "stream_peer_tcp_winsock.h" - -#include <winsock2.h> -#include <ws2tcpip.h> - -#include "drivers/unix/socket_helpers.h" - -int winsock_refcount = 0; - -StreamPeerTCP *StreamPeerTCPWinsock::_create() { - - return memnew(StreamPeerTCPWinsock); -}; - -void StreamPeerTCPWinsock::make_default() { - - StreamPeerTCP::_create = StreamPeerTCPWinsock::_create; - - if (winsock_refcount == 0) { - WSADATA data; - WSAStartup(MAKEWORD(2, 2), &data); - }; - ++winsock_refcount; -}; - -void StreamPeerTCPWinsock::cleanup() { - - --winsock_refcount; - if (winsock_refcount == 0) { - - WSACleanup(); - }; -}; - -Error StreamPeerTCPWinsock::_block(int p_sockfd, bool p_read, bool p_write) const { - - fd_set read, write; - FD_ZERO(&read); - FD_ZERO(&write); - - if (p_read) - FD_SET(p_sockfd, &read); - if (p_write) - FD_SET(p_sockfd, &write); - - int ret = select(p_sockfd + 1, &read, &write, NULL, NULL); // block forever - return ret < 0 ? FAILED : OK; -}; - -Error StreamPeerTCPWinsock::_poll_connection() const { - - ERR_FAIL_COND_V(status != STATUS_CONNECTING || sockfd == INVALID_SOCKET, FAILED); - - struct sockaddr_storage their_addr; - size_t addr_size = _set_sockaddr(&their_addr, peer_host, peer_port, sock_type); - - if (::connect(sockfd, (struct sockaddr *)&their_addr, addr_size) == SOCKET_ERROR) { - - int err = WSAGetLastError(); - if (err == WSAEISCONN) { - status = STATUS_CONNECTED; - return OK; - }; - - if (err == WSAEINPROGRESS || err == WSAEALREADY) { - return OK; - } - - status = STATUS_ERROR; - return ERR_CONNECTION_ERROR; - } else { - - status = STATUS_CONNECTED; - return OK; - }; - - return OK; -}; - -Error StreamPeerTCPWinsock::write(const uint8_t *p_data, int p_bytes, int &r_sent, bool p_block) { - - if (status == STATUS_NONE || status == STATUS_ERROR) { - - return FAILED; - }; - - if (status != STATUS_CONNECTED) { - - if (_poll_connection() != OK) { - - return FAILED; - }; - - if (status != STATUS_CONNECTED) { - r_sent = 0; - return OK; - }; - }; - - int data_to_send = p_bytes; - const uint8_t *offset = p_data; - if (sockfd == -1) return FAILED; - int total_sent = 0; - - while (data_to_send) { - - int sent_amount = send(sockfd, (const char *)offset, data_to_send, 0); - - if (sent_amount == -1) { - - if (WSAGetLastError() != WSAEWOULDBLOCK) { - - perror("Nothing sent"); - disconnect_from_host(); - ERR_PRINT("Server disconnected!\n"); - return FAILED; - }; - - if (!p_block) { - r_sent = total_sent; - return OK; - }; - - _block(sockfd, false, true); - } else { - - data_to_send -= sent_amount; - offset += sent_amount; - total_sent += sent_amount; - }; - } - - r_sent = total_sent; - - return OK; -}; - -Error StreamPeerTCPWinsock::read(uint8_t *p_buffer, int p_bytes, int &r_received, bool p_block) { - - if (!is_connected_to_host()) { - - return FAILED; - }; - - if (status != STATUS_CONNECTED) { - - if (_poll_connection() != OK) { - - return FAILED; - }; - - if (status != STATUS_CONNECTED) { - r_received = 0; - return OK; - }; - }; - - int to_read = p_bytes; - int total_read = 0; - - while (to_read) { - - int read = recv(sockfd, (char *)p_buffer + total_read, to_read, 0); - - if (read == -1) { - - if (WSAGetLastError() != WSAEWOULDBLOCK) { - - perror("Nothing read"); - disconnect_from_host(); - ERR_PRINT("Server disconnected!\n"); - return FAILED; - }; - - if (!p_block) { - - r_received = total_read; - return OK; - }; - _block(sockfd, true, false); - } else if (read == 0) { - disconnect_from_host(); - r_received = total_read; - return ERR_FILE_EOF; - } else { - - to_read -= read; - total_read += read; - }; - }; - - r_received = total_read; - - return OK; -}; - -Error StreamPeerTCPWinsock::put_data(const uint8_t *p_data, int p_bytes) { - - int total; - return write(p_data, p_bytes, total, true); -}; - -Error StreamPeerTCPWinsock::put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) { - - return write(p_data, p_bytes, r_sent, false); -}; - -Error StreamPeerTCPWinsock::get_data(uint8_t *p_buffer, int p_bytes) { - - int total; - return read(p_buffer, p_bytes, total, true); -}; - -Error StreamPeerTCPWinsock::get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) { - - return read(p_buffer, p_bytes, r_received, false); -}; - -StreamPeerTCP::Status StreamPeerTCPWinsock::get_status() const { - - if (status == STATUS_CONNECTING) { - _poll_connection(); - }; - - return status; -}; - -bool StreamPeerTCPWinsock::is_connected_to_host() const { - - if (status == STATUS_NONE || status == STATUS_ERROR) { - - return false; - }; - if (status != STATUS_CONNECTED) { - return true; - }; - - return (sockfd != INVALID_SOCKET); -}; - -void StreamPeerTCPWinsock::disconnect_from_host() { - - if (sockfd != INVALID_SOCKET) - closesocket(sockfd); - sockfd = INVALID_SOCKET; - sock_type = IP::TYPE_NONE; - - status = STATUS_NONE; - - peer_host = IP_Address(); - peer_port = 0; -}; - -void StreamPeerTCPWinsock::set_socket(int p_sockfd, IP_Address p_host, int p_port, IP::Type p_sock_type) { - - sockfd = p_sockfd; - sock_type = p_sock_type; - status = STATUS_CONNECTING; - peer_host = p_host; - peer_port = p_port; -}; - -Error StreamPeerTCPWinsock::connect_to_host(const IP_Address &p_host, uint16_t p_port) { - - ERR_FAIL_COND_V(!p_host.is_valid(), ERR_INVALID_PARAMETER); - - sock_type = p_host.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6; - sockfd = _socket_create(sock_type, SOCK_STREAM, IPPROTO_TCP); - if (sockfd == INVALID_SOCKET) { - ERR_PRINT("Socket creation failed!"); - disconnect_from_host(); - //perror("socket"); - return FAILED; - }; - - unsigned long par = 1; - if (ioctlsocket(sockfd, FIONBIO, &par)) { - perror("setting non-block mode"); - disconnect_from_host(); - return FAILED; - }; - - struct sockaddr_storage their_addr; - size_t addr_size = _set_sockaddr(&their_addr, p_host, p_port, sock_type); - - if (::connect(sockfd, (struct sockaddr *)&their_addr, addr_size) == SOCKET_ERROR) { - - if (WSAGetLastError() != WSAEWOULDBLOCK) { - ERR_PRINT("Connection to remote host failed!"); - disconnect_from_host(); - return FAILED; - }; - status = STATUS_CONNECTING; - } else { - status = STATUS_CONNECTED; - }; - - peer_host = p_host; - peer_port = p_port; - - return OK; -}; - -void StreamPeerTCPWinsock::set_no_delay(bool p_enabled) { - ERR_FAIL_COND(!is_connected_to_host()); - int flag = p_enabled ? 1 : 0; - if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int)) != 0) { - ERR_PRINT("Unable to set TCP no delay option"); - } -} - -int StreamPeerTCPWinsock::get_available_bytes() const { - - unsigned long len; - int ret = ioctlsocket(sockfd, FIONREAD, &len); - ERR_FAIL_COND_V(ret == -1, 0) - return len; -} - -IP_Address StreamPeerTCPWinsock::get_connected_host() const { - - return peer_host; -}; - -uint16_t StreamPeerTCPWinsock::get_connected_port() const { - - return peer_port; -}; - -StreamPeerTCPWinsock::StreamPeerTCPWinsock() { - - sock_type = IP::TYPE_NONE; - sockfd = INVALID_SOCKET; - status = STATUS_NONE; - peer_port = 0; -}; - -StreamPeerTCPWinsock::~StreamPeerTCPWinsock() { - - disconnect_from_host(); -}; - -#endif diff --git a/drivers/windows/tcp_server_winsock.cpp b/drivers/windows/tcp_server_winsock.cpp deleted file mode 100644 index ddb955549f..0000000000 --- a/drivers/windows/tcp_server_winsock.cpp +++ /dev/null @@ -1,189 +0,0 @@ -/*************************************************************************/ -/* tcp_server_winsock.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifdef WINDOWS_ENABLED - -#include "tcp_server_winsock.h" - -#include "stream_peer_tcp_winsock.h" - -#include <winsock2.h> -#include <ws2tcpip.h> - -#include "drivers/unix/socket_helpers.h" - -extern int winsock_refcount; - -TCP_Server *TCPServerWinsock::_create() { - - return memnew(TCPServerWinsock); -}; - -void TCPServerWinsock::make_default() { - - TCP_Server::_create = TCPServerWinsock::_create; - - if (winsock_refcount == 0) { - WSADATA data; - WSAStartup(MAKEWORD(2, 2), &data); - }; - ++winsock_refcount; -}; - -void TCPServerWinsock::cleanup() { - - --winsock_refcount; - if (winsock_refcount == 0) { - - WSACleanup(); - }; -}; - -Error TCPServerWinsock::listen(uint16_t p_port, const IP_Address &p_bind_address) { - - ERR_FAIL_COND_V(listen_sockfd != -1, ERR_ALREADY_IN_USE); - ERR_FAIL_COND_V(!p_bind_address.is_valid() && !p_bind_address.is_wildcard(), ERR_INVALID_PARAMETER); - - int sockfd; - sock_type = IP::TYPE_ANY; - - // If the bind address is valid use its type as the socket type - if (p_bind_address.is_valid()) - sock_type = p_bind_address.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6; - - sockfd = _socket_create(sock_type, SOCK_STREAM, IPPROTO_TCP); - ERR_FAIL_COND_V(sockfd == INVALID_SOCKET, FAILED); - - unsigned long par = 1; - if (ioctlsocket(sockfd, FIONBIO, &par)) { - perror("setting non-block mode"); - stop(); - return FAILED; - }; - - struct sockaddr_storage my_addr; - size_t addr_size = _set_listen_sockaddr(&my_addr, p_port, sock_type, p_bind_address); - - int reuse = 1; - if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0) { - - printf("REUSEADDR failed!"); - } - - if (bind(sockfd, (struct sockaddr *)&my_addr, addr_size) != SOCKET_ERROR) { - - if (::listen(sockfd, SOMAXCONN) == SOCKET_ERROR) { - - closesocket(sockfd); - ERR_FAIL_V(FAILED); - }; - } else { - closesocket(sockfd); - return ERR_ALREADY_IN_USE; - }; - - if (listen_sockfd != INVALID_SOCKET) { - - stop(); - }; - - listen_sockfd = sockfd; - - return OK; -}; - -bool TCPServerWinsock::is_connection_available() const { - - if (listen_sockfd == -1) { - return false; - }; - - timeval timeout; - timeout.tv_sec = 0; - timeout.tv_usec = 0; - - fd_set pfd; - FD_ZERO(&pfd); - FD_SET(listen_sockfd, &pfd); - - int ret = select(listen_sockfd + 1, &pfd, NULL, NULL, &timeout); - ERR_FAIL_COND_V(ret < 0, 0); - - if (ret && (FD_ISSET(listen_sockfd, &pfd))) { - - return true; - }; - - return false; -}; - -Ref<StreamPeerTCP> TCPServerWinsock::take_connection() { - - if (!is_connection_available()) { - return NULL; - }; - - struct sockaddr_storage their_addr; - int sin_size = sizeof(their_addr); - int fd = accept(listen_sockfd, (struct sockaddr *)&their_addr, &sin_size); - ERR_FAIL_COND_V(fd == INVALID_SOCKET, NULL); - - Ref<StreamPeerTCPWinsock> conn = memnew(StreamPeerTCPWinsock); - IP_Address ip; - int port; - _set_ip_addr_port(ip, port, &their_addr); - - conn->set_socket(fd, ip, port, sock_type); - - return conn; -}; - -void TCPServerWinsock::stop() { - - if (listen_sockfd != INVALID_SOCKET) { - closesocket(listen_sockfd); - }; - - listen_sockfd = -1; - sock_type = IP::TYPE_NONE; -}; - -TCPServerWinsock::TCPServerWinsock() { - - listen_sockfd = INVALID_SOCKET; - sock_type = IP::TYPE_NONE; -}; - -TCPServerWinsock::~TCPServerWinsock() { - - stop(); -}; - -#endif diff --git a/drivers/windows/tcp_server_winsock.h b/drivers/windows/tcp_server_winsock.h deleted file mode 100644 index a6979db42d..0000000000 --- a/drivers/windows/tcp_server_winsock.h +++ /dev/null @@ -1,61 +0,0 @@ -/*************************************************************************/ -/* tcp_server_winsock.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifdef WINDOWS_ENABLED - -#ifndef TCP_SERVER_WINSOCK_H -#define TCP_SERVER_WINSOCK_H - -#include "core/io/tcp_server.h" - -class TCPServerWinsock : public TCP_Server { - - int listen_sockfd; - IP::Type sock_type; - - static TCP_Server *_create(); - -public: - virtual Error listen(uint16_t p_port, const IP_Address &p_bind_address = IP_Address("*")); - virtual bool is_connection_available() const; - virtual Ref<StreamPeerTCP> take_connection(); - - virtual void stop(); //stop listening - - static void make_default(); - static void cleanup(); - - TCPServerWinsock(); - ~TCPServerWinsock(); -}; - -#endif - -#endif diff --git a/editor/fileserver/editor_file_server.cpp b/editor/fileserver/editor_file_server.cpp index d6e89d0573..27fe716855 100644 --- a/editor/fileserver/editor_file_server.cpp +++ b/editor/fileserver/editor_file_server.cpp @@ -330,7 +330,7 @@ void EditorFileServer::stop() { EditorFileServer::EditorFileServer() { - server = TCP_Server::create_ref(); + server.instance(); wait_mutex = Mutex::create(); quit = false; active = false; diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 706bda4089..f25ca4786e 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -946,7 +946,7 @@ void ScriptEditor::_menu_option(int p_option) { switch (p_option) { case FILE_NEW: { - script_create_dialog->config("Node", ".gd"); + script_create_dialog->config("Node", "new_script"); script_create_dialog->popup_centered(Size2(300, 300) * EDSCALE); } break; case FILE_NEW_TEXTFILE: { @@ -1749,7 +1749,7 @@ void ScriptEditor::_update_script_names() { } break; case DISPLAY_DIR_AND_NAME: { if (!path.get_base_dir().get_file().empty()) { - sd.name = path.get_base_dir().get_file() + "/" + name; + sd.name = path.get_base_dir().get_file().plus_file(name); } else { sd.name = name; } @@ -2114,8 +2114,6 @@ void ScriptEditor::_editor_play() { debug_menu->get_popup()->set_item_disabled(debug_menu->get_popup()->get_item_index(DEBUG_STEP), true); debug_menu->get_popup()->set_item_disabled(debug_menu->get_popup()->get_item_index(DEBUG_BREAK), false); debug_menu->get_popup()->set_item_disabled(debug_menu->get_popup()->get_item_index(DEBUG_CONTINUE), true); - - //debugger_gui->start_listening(Globals::get_singleton()->get("debug/debug_port")); } void ScriptEditor::_editor_pause() { diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 5f2841d2c0..9461f39aeb 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -224,7 +224,7 @@ void SceneTreeDock::_perform_instance_scenes(const Vector<String> &p_files, Node String new_name = parent->validate_child_name(instanced_scene); ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger(); editor_data->get_undo_redo().add_do_method(sed, "live_debug_instance_node", edited_scene->get_path_to(parent), p_files[i], new_name); - editor_data->get_undo_redo().add_undo_method(sed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)) + "/" + new_name)); + editor_data->get_undo_redo().add_undo_method(sed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).plus_file(new_name))); } editor_data->get_undo_redo().commit_action(); @@ -354,9 +354,9 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { if (path == "") { String root_path = editor_data->get_edited_scene_root()->get_filename(); if (root_path == "") { - path = "res://" + selected->get_name(); + path = String("res://").plus_file(selected->get_name()); } else { - path = root_path.get_base_dir() + "/" + selected->get_name(); + path = root_path.get_base_dir().plus_file(selected->get_name()); } } @@ -535,7 +535,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger(); editor_data->get_undo_redo().add_do_method(sed, "live_debug_duplicate_node", edited_scene->get_path_to(node), dup->get_name()); - editor_data->get_undo_redo().add_undo_method(sed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)) + "/" + dup->get_name())); + editor_data->get_undo_redo().add_undo_method(sed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).plus_file(dup->get_name()))); } editor_data->get_undo_redo().commit_action(); @@ -1429,7 +1429,7 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V } editor_data->get_undo_redo().add_do_method(sed, "live_debug_reparent_node", edited_scene->get_path_to(node), edited_scene->get_path_to(new_parent), new_name, p_position_in_parent + inc); - editor_data->get_undo_redo().add_undo_method(sed, "live_debug_reparent_node", NodePath(String(edited_scene->get_path_to(new_parent)) + "/" + new_name), edited_scene->get_path_to(node->get_parent()), node->get_name(), node->get_index()); + editor_data->get_undo_redo().add_undo_method(sed, "live_debug_reparent_node", NodePath(String(edited_scene->get_path_to(new_parent)).plus_file(new_name)), edited_scene->get_path_to(node->get_parent()), node->get_name(), node->get_index()); if (p_keep_global_xform) { if (Object::cast_to<Node2D>(node)) @@ -1661,7 +1661,7 @@ void SceneTreeDock::_create() { String new_name = parent->validate_child_name(child); ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger(); editor_data->get_undo_redo().add_do_method(sed, "live_debug_create_node", edited_scene->get_path_to(parent), child->get_class(), new_name); - editor_data->get_undo_redo().add_undo_method(sed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)) + "/" + new_name)); + editor_data->get_undo_redo().add_undo_method(sed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).plus_file(new_name))); } else { diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index 8c36a71d71..be255ba4aa 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -56,6 +56,7 @@ void ScriptCreateDialog::config(const String &p_base_name, const String &p_base_ class_name->deselect(); parent_name->set_text(p_base_name); parent_name->deselect(); + if (p_base_path != "") { initial_bp = p_base_path.get_basename(); file_path->set_text(initial_bp + "." + ScriptServer::get_language(language_menu->get_selected())->get_extension()); @@ -359,7 +360,7 @@ void ScriptCreateDialog::_path_changed(const String &p_path) { is_path_valid = false; is_new_script_created = true; - String p = p_path; + String p = p_path.strip_edges(); if (p == "") { _msg_path_valid(false, TTR("Path is empty")); @@ -367,6 +368,12 @@ void ScriptCreateDialog::_path_changed(const String &p_path) { return; } + if (p.get_file().get_basename() == "") { + _msg_path_valid(false, TTR("Filename is empty")); + _update_dialog(); + return; + } + p = ProjectSettings::get_singleton()->localize_path(p); if (!p.begins_with("res://")) { _msg_path_valid(false, TTR("Path is not local")); @@ -443,12 +450,6 @@ void ScriptCreateDialog::_path_changed(const String &p_path) { return; } - if (p.get_file().get_basename() == "") { - _msg_path_valid(false, TTR("Filename is empty")); - _update_dialog(); - return; - } - /* All checks passed */ is_path_valid = true; diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp index 7a97531932..c07220d42c 100644 --- a/editor/script_editor_debugger.cpp +++ b/editor/script_editor_debugger.cpp @@ -1987,7 +1987,7 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) { inspector->connect("object_id_selected", this, "_scene_tree_property_select_object"); sc->add_child(inspector); - server = TCP_Server::create_ref(); + server.instance(); pending_in_queue = 0; diff --git a/modules/mono/SCsub b/modules/mono/SCsub index a8e19db022..b3a2d26e4a 100644 --- a/modules/mono/SCsub +++ b/modules/mono/SCsub @@ -77,7 +77,7 @@ env_mono.add_source_files(env.modules_sources, 'utils/*.cpp') if env['tools']: env_mono.add_source_files(env.modules_sources, 'editor/*.cpp') # NOTE: It is safe to generate this file here, since this is still executed serially - make_cs_files_header('glue/cs_files', 'glue/cs_compressed.gen.h', 'glue/cs_glue_version.gen.h') + make_cs_files_header('glue/Managed/Files', 'glue/cs_compressed.gen.h', 'glue/cs_glue_version.gen.h') vars = Variables() vars.Add(BoolVariable('mono_glue', 'Build with the mono glue sources', True)) diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index f15114ef1d..b9209fce92 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -1456,7 +1456,7 @@ MonoObject *CSharpInstance::_internal_new_managed() { return mono_object; } -bool CSharpInstance::mono_object_disposed(MonoObject *p_obj) { +void CSharpInstance::mono_object_disposed(MonoObject *p_obj) { #ifdef DEBUG_ENABLED CRASH_COND(base_ref == true); @@ -1465,7 +1465,7 @@ bool CSharpInstance::mono_object_disposed(MonoObject *p_obj) { CSharpLanguage::get_singleton()->release_script_gchandle(p_obj, gchandle); } -bool CSharpInstance::mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_finalizer, bool &r_owner_deleted) { +void CSharpInstance::mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_finalizer, bool &r_owner_deleted) { #ifdef DEBUG_ENABLED CRASH_COND(base_ref == false); @@ -1928,6 +1928,10 @@ bool CSharpScript::_get_signal(GDMonoClass *p_class, GDMonoClass *p_delegate, Ve } #ifdef TOOLS_ENABLED +/** + * Returns false if there was an error, otherwise true. + * If there was an error, r_prop_info and r_exported are not assigned any value. + */ bool CSharpScript::_get_member_export(GDMonoClass *p_class, GDMonoClassMember *p_member, PropertyInfo &r_prop_info, bool &r_exported) { StringName name = p_member->get_name(); @@ -1953,49 +1957,100 @@ bool CSharpScript::_get_member_export(GDMonoClass *p_class, GDMonoClassMember *p Variant::Type variant_type = GDMonoMarshal::managed_to_variant_type(type); - if (p_member->has_attribute(CACHED_CLASS(ExportAttribute))) { - if (p_member->get_member_type() == GDMonoClassMember::MEMBER_TYPE_PROPERTY) { - GDMonoProperty *property = static_cast<GDMonoProperty *>(p_member); - if (!property->has_getter() || !property->has_setter()) { - ERR_PRINTS("Cannot export property because it does not provide a getter or a setter: " + p_class->get_full_name() + "." + name.operator String()); - return false; - } + if (!p_member->has_attribute(CACHED_CLASS(ExportAttribute))) { + r_prop_info = PropertyInfo(variant_type, name.operator String(), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_SCRIPT_VARIABLE); + r_exported = false; + return true; + } + + if (p_member->get_member_type() == GDMonoClassMember::MEMBER_TYPE_PROPERTY) { + GDMonoProperty *property = static_cast<GDMonoProperty *>(p_member); + if (!property->has_getter() || !property->has_setter()) { + ERR_PRINTS("Cannot export property because it does not provide a getter or a setter: " + p_class->get_full_name() + "." + name.operator String()); + return false; } + } - MonoObject *attr = p_member->get_attribute(CACHED_CLASS(ExportAttribute)); + MonoObject *attr = p_member->get_attribute(CACHED_CLASS(ExportAttribute)); - PropertyHint hint = PROPERTY_HINT_NONE; - String hint_string; + PropertyHint hint = PROPERTY_HINT_NONE; + String hint_string; - if (variant_type == Variant::NIL) { - ERR_PRINTS("Unknown type of exported member: " + p_class->get_full_name() + "." + name.operator String()); - return false; - } else if (variant_type == Variant::INT && type.type_encoding == MONO_TYPE_VALUETYPE && mono_class_is_enum(type.type_class->get_mono_ptr())) { - variant_type = Variant::INT; - hint = PROPERTY_HINT_ENUM; + if (variant_type == Variant::NIL) { + ERR_PRINTS("Unknown type of exported member: " + p_class->get_full_name() + "." + name.operator String()); + return false; + } else if (variant_type == Variant::INT && type.type_encoding == MONO_TYPE_VALUETYPE && mono_class_is_enum(type.type_class->get_mono_ptr())) { + variant_type = Variant::INT; + hint = PROPERTY_HINT_ENUM; + + Vector<MonoClassField *> fields = type.type_class->get_enum_fields(); - Vector<MonoClassField *> fields = type.type_class->get_enum_fields(); + MonoType *enum_basetype = mono_class_enum_basetype(type.type_class->get_mono_ptr()); - for (int i = 0; i < fields.size(); i++) { - if (i > 0) - hint_string += ","; - hint_string += mono_field_get_name(fields[i]); + String name_only_hint_string; + + // True: enum Foo { Bar, Baz, Quux } + // True: enum Foo { Bar = 0, Baz = 1, Quux = 2 } + // False: enum Foo { Bar = 0, Baz = 7, Quux = 5 } + bool uses_default_values = true; + + for (int i = 0; i < fields.size(); i++) { + MonoClassField *field = fields[i]; + + if (i > 0) { + hint_string += ","; + name_only_hint_string += ","; } - } else if (variant_type == Variant::OBJECT && CACHED_CLASS(GodotReference)->is_assignable_from(type.type_class)) { - hint = PROPERTY_HINT_RESOURCE_TYPE; - hint_string = NATIVE_GDMONOCLASS_NAME(type.type_class); - } else { - hint = PropertyHint(CACHED_FIELD(ExportAttribute, hint)->get_int_value(attr)); - hint_string = CACHED_FIELD(ExportAttribute, hintString)->get_string_value(attr); + + String enum_field_name = mono_field_get_name(field); + hint_string += enum_field_name; + name_only_hint_string += enum_field_name; + + // TODO: + // Instead of using mono_field_get_value_object, we can do this without boxing. Check the + // internal mono functions: ves_icall_System_Enum_GetEnumValuesAndNames and the get_enum_field. + + MonoObject *val_obj = mono_field_get_value_object(mono_domain_get(), field, NULL); + + if (val_obj == NULL) { + ERR_PRINTS("Failed to get '" + enum_field_name + "' constant enum value of exported member: " + + p_class->get_full_name() + "." + name.operator String()); + return false; + } + + bool r_error; + uint64_t val = GDMonoUtils::unbox_enum_value(val_obj, enum_basetype, r_error); + if (r_error) { + ERR_PRINTS("Failed to unbox '" + enum_field_name + "' constant enum value of exported member: " + + p_class->get_full_name() + "." + name.operator String()); + return false; + } + + if (val != i) { + uses_default_values = false; + } + + hint_string += ":"; + hint_string += String::num_uint64(val); } - r_prop_info = PropertyInfo(variant_type, name.operator String(), hint, hint_string, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE); - r_exported = true; + if (uses_default_values) { + // If we use the format NAME:VAL, that's what the editor displays. + // That's annoying if the user is not using custom values for the enum constants. + // This may not be needed in the future if the editor is changed to not display values. + hint_string = name_only_hint_string; + } + } else if (variant_type == Variant::OBJECT && CACHED_CLASS(GodotReference)->is_assignable_from(type.type_class)) { + hint = PROPERTY_HINT_RESOURCE_TYPE; + hint_string = NATIVE_GDMONOCLASS_NAME(type.type_class); } else { - r_prop_info = PropertyInfo(variant_type, name.operator String(), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_SCRIPT_VARIABLE); - r_exported = false; + hint = PropertyHint(CACHED_FIELD(ExportAttribute, hint)->get_int_value(attr)); + hint_string = CACHED_FIELD(ExportAttribute, hintString)->get_string_value(attr); } + r_prop_info = PropertyInfo(variant_type, name.operator String(), hint, hint_string, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE); + r_exported = true; + return true; } #endif diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index fa399bb187..8b0a095890 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -215,8 +215,8 @@ public: virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount); virtual void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount); - bool mono_object_disposed(MonoObject *p_obj); - bool mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_finalizer, bool &r_owner_deleted); + void mono_object_disposed(MonoObject *p_obj); + void mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_finalizer, bool &r_owner_deleted); virtual void refcount_incremented(); virtual bool refcount_decremented(); diff --git a/modules/mono/glue/cs_files/AABB.cs b/modules/mono/glue/Managed/Files/AABB.cs index 66490b5e25..66490b5e25 100644 --- a/modules/mono/glue/cs_files/AABB.cs +++ b/modules/mono/glue/Managed/Files/AABB.cs diff --git a/modules/mono/glue/cs_files/Array.cs b/modules/mono/glue/Managed/Files/Array.cs index c80cb7cc83..c80cb7cc83 100644 --- a/modules/mono/glue/cs_files/Array.cs +++ b/modules/mono/glue/Managed/Files/Array.cs diff --git a/modules/mono/glue/cs_files/Attributes/ExportAttribute.cs b/modules/mono/glue/Managed/Files/Attributes/ExportAttribute.cs index 6adf044886..6adf044886 100644 --- a/modules/mono/glue/cs_files/Attributes/ExportAttribute.cs +++ b/modules/mono/glue/Managed/Files/Attributes/ExportAttribute.cs diff --git a/modules/mono/glue/cs_files/Attributes/GodotMethodAttribute.cs b/modules/mono/glue/Managed/Files/Attributes/GodotMethodAttribute.cs index 55848769d5..55848769d5 100644 --- a/modules/mono/glue/cs_files/Attributes/GodotMethodAttribute.cs +++ b/modules/mono/glue/Managed/Files/Attributes/GodotMethodAttribute.cs diff --git a/modules/mono/glue/cs_files/Attributes/RPCAttributes.cs b/modules/mono/glue/Managed/Files/Attributes/RPCAttributes.cs index 6bf9560bfa..6bf9560bfa 100644 --- a/modules/mono/glue/cs_files/Attributes/RPCAttributes.cs +++ b/modules/mono/glue/Managed/Files/Attributes/RPCAttributes.cs diff --git a/modules/mono/glue/cs_files/Attributes/SignalAttribute.cs b/modules/mono/glue/Managed/Files/Attributes/SignalAttribute.cs index 3957387be9..3957387be9 100644 --- a/modules/mono/glue/cs_files/Attributes/SignalAttribute.cs +++ b/modules/mono/glue/Managed/Files/Attributes/SignalAttribute.cs diff --git a/modules/mono/glue/cs_files/Attributes/ToolAttribute.cs b/modules/mono/glue/Managed/Files/Attributes/ToolAttribute.cs index d0437409af..d0437409af 100644 --- a/modules/mono/glue/cs_files/Attributes/ToolAttribute.cs +++ b/modules/mono/glue/Managed/Files/Attributes/ToolAttribute.cs diff --git a/modules/mono/glue/cs_files/Basis.cs b/modules/mono/glue/Managed/Files/Basis.cs index ec96a9e2fa..ec96a9e2fa 100644 --- a/modules/mono/glue/cs_files/Basis.cs +++ b/modules/mono/glue/Managed/Files/Basis.cs diff --git a/modules/mono/glue/cs_files/Color.cs b/modules/mono/glue/Managed/Files/Color.cs index 88cb8524b8..88cb8524b8 100644 --- a/modules/mono/glue/cs_files/Color.cs +++ b/modules/mono/glue/Managed/Files/Color.cs diff --git a/modules/mono/glue/cs_files/DebuggingUtils.cs b/modules/mono/glue/Managed/Files/DebuggingUtils.cs index b27816084e..b27816084e 100644 --- a/modules/mono/glue/cs_files/DebuggingUtils.cs +++ b/modules/mono/glue/Managed/Files/DebuggingUtils.cs diff --git a/modules/mono/glue/cs_files/Dictionary.cs b/modules/mono/glue/Managed/Files/Dictionary.cs index 523e48c31a..523e48c31a 100644 --- a/modules/mono/glue/cs_files/Dictionary.cs +++ b/modules/mono/glue/Managed/Files/Dictionary.cs diff --git a/modules/mono/glue/cs_files/Extensions/NodeExtensions.cs b/modules/mono/glue/Managed/Files/Extensions/NodeExtensions.cs index 71534d7782..71534d7782 100644 --- a/modules/mono/glue/cs_files/Extensions/NodeExtensions.cs +++ b/modules/mono/glue/Managed/Files/Extensions/NodeExtensions.cs diff --git a/modules/mono/glue/cs_files/Extensions/ObjectExtensions.cs b/modules/mono/glue/Managed/Files/Extensions/ObjectExtensions.cs index 9ef0959750..9ef0959750 100644 --- a/modules/mono/glue/cs_files/Extensions/ObjectExtensions.cs +++ b/modules/mono/glue/Managed/Files/Extensions/ObjectExtensions.cs diff --git a/modules/mono/glue/cs_files/Extensions/ResourceLoaderExtensions.cs b/modules/mono/glue/Managed/Files/Extensions/ResourceLoaderExtensions.cs index ceecc589e6..ceecc589e6 100644 --- a/modules/mono/glue/cs_files/Extensions/ResourceLoaderExtensions.cs +++ b/modules/mono/glue/Managed/Files/Extensions/ResourceLoaderExtensions.cs diff --git a/modules/mono/glue/cs_files/GD.cs b/modules/mono/glue/Managed/Files/GD.cs index 264be23588..264be23588 100644 --- a/modules/mono/glue/cs_files/GD.cs +++ b/modules/mono/glue/Managed/Files/GD.cs diff --git a/modules/mono/glue/cs_files/GodotSynchronizationContext.cs b/modules/mono/glue/Managed/Files/GodotSynchronizationContext.cs index e727781d63..e727781d63 100644 --- a/modules/mono/glue/cs_files/GodotSynchronizationContext.cs +++ b/modules/mono/glue/Managed/Files/GodotSynchronizationContext.cs diff --git a/modules/mono/glue/cs_files/GodotTaskScheduler.cs b/modules/mono/glue/Managed/Files/GodotTaskScheduler.cs index 9a40fef5a9..9a40fef5a9 100644 --- a/modules/mono/glue/cs_files/GodotTaskScheduler.cs +++ b/modules/mono/glue/Managed/Files/GodotTaskScheduler.cs diff --git a/modules/mono/glue/cs_files/Interfaces/IAwaitable.cs b/modules/mono/glue/Managed/Files/Interfaces/IAwaitable.cs index 0397957d00..0397957d00 100644 --- a/modules/mono/glue/cs_files/Interfaces/IAwaitable.cs +++ b/modules/mono/glue/Managed/Files/Interfaces/IAwaitable.cs diff --git a/modules/mono/glue/cs_files/Interfaces/IAwaiter.cs b/modules/mono/glue/Managed/Files/Interfaces/IAwaiter.cs index d3be9d781c..d3be9d781c 100644 --- a/modules/mono/glue/cs_files/Interfaces/IAwaiter.cs +++ b/modules/mono/glue/Managed/Files/Interfaces/IAwaiter.cs diff --git a/modules/mono/glue/cs_files/MarshalUtils.cs b/modules/mono/glue/Managed/Files/MarshalUtils.cs index f7699a15bf..f7699a15bf 100644 --- a/modules/mono/glue/cs_files/MarshalUtils.cs +++ b/modules/mono/glue/Managed/Files/MarshalUtils.cs diff --git a/modules/mono/glue/cs_files/Mathf.cs b/modules/mono/glue/Managed/Files/Mathf.cs index a89dfe5f27..a89dfe5f27 100644 --- a/modules/mono/glue/cs_files/Mathf.cs +++ b/modules/mono/glue/Managed/Files/Mathf.cs diff --git a/modules/mono/glue/cs_files/MathfEx.cs b/modules/mono/glue/Managed/Files/MathfEx.cs index 739b7fb568..739b7fb568 100644 --- a/modules/mono/glue/cs_files/MathfEx.cs +++ b/modules/mono/glue/Managed/Files/MathfEx.cs diff --git a/modules/mono/glue/cs_files/NodePath.cs b/modules/mono/glue/Managed/Files/NodePath.cs index 2c89bec87f..2c89bec87f 100644 --- a/modules/mono/glue/cs_files/NodePath.cs +++ b/modules/mono/glue/Managed/Files/NodePath.cs diff --git a/modules/mono/glue/cs_files/Object.base.cs b/modules/mono/glue/Managed/Files/Object.base.cs index 30490a715f..30490a715f 100644 --- a/modules/mono/glue/cs_files/Object.base.cs +++ b/modules/mono/glue/Managed/Files/Object.base.cs diff --git a/modules/mono/glue/cs_files/Plane.cs b/modules/mono/glue/Managed/Files/Plane.cs index 9611dce11e..9611dce11e 100644 --- a/modules/mono/glue/cs_files/Plane.cs +++ b/modules/mono/glue/Managed/Files/Plane.cs diff --git a/modules/mono/glue/cs_files/Quat.cs b/modules/mono/glue/Managed/Files/Quat.cs index eaa027eb69..eaa027eb69 100644 --- a/modules/mono/glue/cs_files/Quat.cs +++ b/modules/mono/glue/Managed/Files/Quat.cs diff --git a/modules/mono/glue/cs_files/RID.cs b/modules/mono/glue/Managed/Files/RID.cs index b862b8cac0..b862b8cac0 100644 --- a/modules/mono/glue/cs_files/RID.cs +++ b/modules/mono/glue/Managed/Files/RID.cs diff --git a/modules/mono/glue/cs_files/Rect2.cs b/modules/mono/glue/Managed/Files/Rect2.cs index cb25c267bc..cb25c267bc 100644 --- a/modules/mono/glue/cs_files/Rect2.cs +++ b/modules/mono/glue/Managed/Files/Rect2.cs diff --git a/modules/mono/glue/cs_files/SignalAwaiter.cs b/modules/mono/glue/Managed/Files/SignalAwaiter.cs index 9483b6ffb4..9483b6ffb4 100644 --- a/modules/mono/glue/cs_files/SignalAwaiter.cs +++ b/modules/mono/glue/Managed/Files/SignalAwaiter.cs diff --git a/modules/mono/glue/cs_files/StringExtensions.cs b/modules/mono/glue/Managed/Files/StringExtensions.cs index 21c9be98c1..21c9be98c1 100644 --- a/modules/mono/glue/cs_files/StringExtensions.cs +++ b/modules/mono/glue/Managed/Files/StringExtensions.cs diff --git a/modules/mono/glue/cs_files/Transform.cs b/modules/mono/glue/Managed/Files/Transform.cs index e432d5b52c..e432d5b52c 100644 --- a/modules/mono/glue/cs_files/Transform.cs +++ b/modules/mono/glue/Managed/Files/Transform.cs diff --git a/modules/mono/glue/cs_files/Transform2D.cs b/modules/mono/glue/Managed/Files/Transform2D.cs index 8d30833066..8d30833066 100644 --- a/modules/mono/glue/cs_files/Transform2D.cs +++ b/modules/mono/glue/Managed/Files/Transform2D.cs diff --git a/modules/mono/glue/cs_files/Vector2.cs b/modules/mono/glue/Managed/Files/Vector2.cs index 080b8802ba..080b8802ba 100644 --- a/modules/mono/glue/cs_files/Vector2.cs +++ b/modules/mono/glue/Managed/Files/Vector2.cs diff --git a/modules/mono/glue/cs_files/Vector3.cs b/modules/mono/glue/Managed/Files/Vector3.cs index 6fffe5e4d6..6fffe5e4d6 100644 --- a/modules/mono/glue/cs_files/Vector3.cs +++ b/modules/mono/glue/Managed/Files/Vector3.cs diff --git a/modules/mono/glue/Managed/IgnoredFiles/Enums.cs b/modules/mono/glue/Managed/IgnoredFiles/Enums.cs new file mode 100644 index 0000000000..05f1abcf93 --- /dev/null +++ b/modules/mono/glue/Managed/IgnoredFiles/Enums.cs @@ -0,0 +1,21 @@ + +namespace Godot +{ + public enum Margin + { + Left = 0, + Top = 1, + Right = 2, + Bottom = 3 + } + + public enum Error + { + Ok = 0 + } + + public enum PropertyHint + { + None = 0 + } +} diff --git a/modules/mono/glue/Managed/IgnoredFiles/FuncRef.cs b/modules/mono/glue/Managed/IgnoredFiles/FuncRef.cs new file mode 100644 index 0000000000..83504fe49f --- /dev/null +++ b/modules/mono/glue/Managed/IgnoredFiles/FuncRef.cs @@ -0,0 +1,17 @@ +using System; + +namespace Godot +{ + public partial class FuncRef + { + public void SetInstance(Object instance) + { + throw new NotImplementedException(); + } + + public void SetFunction(string name) + { + throw new NotImplementedException(); + } + } +} diff --git a/modules/mono/glue/Managed/IgnoredFiles/Node.cs b/modules/mono/glue/Managed/IgnoredFiles/Node.cs new file mode 100644 index 0000000000..99ba0f827a --- /dev/null +++ b/modules/mono/glue/Managed/IgnoredFiles/Node.cs @@ -0,0 +1,28 @@ + +using System; + +namespace Godot +{ + public partial class Node + { + public Node GetChild(int idx) + { + throw new NotImplementedException(); + } + + public Node GetNode(NodePath path) + { + throw new NotImplementedException(); + } + + public Node GetOwner() + { + throw new NotImplementedException(); + } + + public Node GetParent() + { + throw new NotImplementedException(); + } + } +} diff --git a/modules/mono/glue/Managed/IgnoredFiles/Resource.cs b/modules/mono/glue/Managed/IgnoredFiles/Resource.cs new file mode 100644 index 0000000000..cc0a5555b1 --- /dev/null +++ b/modules/mono/glue/Managed/IgnoredFiles/Resource.cs @@ -0,0 +1,7 @@ +namespace Godot +{ + public partial class Resource + { + + } +} diff --git a/modules/mono/glue/Managed/IgnoredFiles/ResourceLoader.cs b/modules/mono/glue/Managed/IgnoredFiles/ResourceLoader.cs new file mode 100644 index 0000000000..6461d35146 --- /dev/null +++ b/modules/mono/glue/Managed/IgnoredFiles/ResourceLoader.cs @@ -0,0 +1,12 @@ +using System; + +namespace Godot +{ + public partial class ResourceLoader + { + public static Resource Load(string path, string typeHint = "", bool pNoCache = false) + { + throw new NotImplementedException(); + } + } +} diff --git a/modules/mono/glue/Managed/IgnoredFiles/WeakRef.cs b/modules/mono/glue/Managed/IgnoredFiles/WeakRef.cs new file mode 100644 index 0000000000..1498b7836b --- /dev/null +++ b/modules/mono/glue/Managed/IgnoredFiles/WeakRef.cs @@ -0,0 +1,7 @@ +namespace Godot +{ + public partial class WeakRef + { + + } +} diff --git a/modules/mono/glue/Managed/Managed.csproj b/modules/mono/glue/Managed/Managed.csproj new file mode 100644 index 0000000000..1f82dde5e7 --- /dev/null +++ b/modules/mono/glue/Managed/Managed.csproj @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">x86</Platform> + <ProjectGuid>{DAA3DEF8-5112-407C-A5E5-6C608CF5F955}</ProjectGuid> + <OutputType>Library</OutputType> + <RootNamespace>Managed</RootNamespace> + <AssemblyName>Managed</AssemblyName> + <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug</OutputPath> + <DefineConstants>DEBUG;</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <ExternalConsole>true</ExternalConsole> + <PlatformTarget>x86</PlatformTarget> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> + <Optimize>true</Optimize> + <OutputPath>bin\Release</OutputPath> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <ExternalConsole>true</ExternalConsole> + <PlatformTarget>x86</PlatformTarget> + </PropertyGroup> + <ItemGroup> + <Reference Include="System" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Files\**\*.cs" /> + <Compile Include="IgnoredFiles\**\*.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> +</Project> diff --git a/modules/mono/glue/Managed/Managed.sln b/modules/mono/glue/Managed/Managed.sln new file mode 100644 index 0000000000..61ddde0fb7 --- /dev/null +++ b/modules/mono/glue/Managed/Managed.sln @@ -0,0 +1,17 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Managed", "Managed.csproj", "{DAA3DEF8-5112-407C-A5E5-6C608CF5F955}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DAA3DEF8-5112-407C-A5E5-6C608CF5F955}.Debug|x86.ActiveCfg = Debug|x86 + {DAA3DEF8-5112-407C-A5E5-6C608CF5F955}.Debug|x86.Build.0 = Debug|x86 + {DAA3DEF8-5112-407C-A5E5-6C608CF5F955}.Release|x86.ActiveCfg = Release|x86 + {DAA3DEF8-5112-407C-A5E5-6C608CF5F955}.Release|x86.Build.0 = Release|x86 + EndGlobalSection +EndGlobal diff --git a/modules/mono/glue/Managed/Properties/AssemblyInfo.cs b/modules/mono/glue/Managed/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..7ed68acad7 --- /dev/null +++ b/modules/mono/glue/Managed/Properties/AssemblyInfo.cs @@ -0,0 +1,26 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("Managed")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] diff --git a/modules/mono/glue/Managed/README.md b/modules/mono/glue/Managed/README.md new file mode 100644 index 0000000000..65e63cae37 --- /dev/null +++ b/modules/mono/glue/Managed/README.md @@ -0,0 +1,5 @@ +The directory `Files` contains C# files from the core assembly project that are not part of the generated API. Any file with the `.cs` extension in this directory will be added to the core assembly project. + +A dummy solution and project is provided to get tooling help while editing these files, like code completion and name refactoring. + +The directory `IgnoredFiles` contains C# files that are needed to build the dummy project but must not be added to the core assembly project. They contain placeholders for the declarations that are part of the generated API. diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp index cc5b5652f8..8fbaca0992 100644 --- a/modules/mono/mono_gd/gd_mono_utils.cpp +++ b/modules/mono/mono_gd/gd_mono_utils.cpp @@ -663,4 +663,33 @@ MonoObject *property_get_value(MonoProperty *p_prop, void *p_obj, void **p_param return ret; } +uint64_t unbox_enum_value(MonoObject *p_boxed, MonoType *p_enum_basetype, bool &r_error) { + r_error = false; + switch (mono_type_get_type(p_enum_basetype)) { + case MONO_TYPE_BOOLEAN: + return (bool)GDMonoMarshal::unbox<MonoBoolean>(p_boxed) ? 1 : 0; + case MONO_TYPE_CHAR: + return GDMonoMarshal::unbox<uint16_t>(p_boxed); + case MONO_TYPE_U1: + return GDMonoMarshal::unbox<uint8_t>(p_boxed); + case MONO_TYPE_U2: + return GDMonoMarshal::unbox<uint16_t>(p_boxed); + case MONO_TYPE_U4: + return GDMonoMarshal::unbox<uint32_t>(p_boxed); + case MONO_TYPE_U8: + return GDMonoMarshal::unbox<uint64_t>(p_boxed); + case MONO_TYPE_I1: + return GDMonoMarshal::unbox<int8_t>(p_boxed); + case MONO_TYPE_I2: + return GDMonoMarshal::unbox<int16_t>(p_boxed); + case MONO_TYPE_I4: + return GDMonoMarshal::unbox<int32_t>(p_boxed); + case MONO_TYPE_I8: + return GDMonoMarshal::unbox<int64_t>(p_boxed); + default: + r_error = true; + return 0; + } +} + } // namespace GDMonoUtils diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h index c8e23f071f..96ff3e8116 100644 --- a/modules/mono/mono_gd/gd_mono_utils.h +++ b/modules/mono/mono_gd/gd_mono_utils.h @@ -240,6 +240,8 @@ MonoString *object_to_string(MonoObject *p_obj, MonoException **p_exc); void property_set_value(MonoProperty *p_prop, void *p_obj, void **p_params, MonoException **p_exc); MonoObject *property_get_value(MonoProperty *p_prop, void *p_obj, void **p_params, MonoException **p_exc); +uint64_t unbox_enum_value(MonoObject *p_boxed, MonoType *p_enum_basetype, bool &r_error); + } // namespace GDMonoUtils #define NATIVE_GDMONOCLASS_NAME(m_class) (GDMonoMarshal::mono_string_to_godot((MonoString *)m_class->get_field(BINDINGS_NATIVE_NAME_FIELD)->get_value(NULL))) diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index df444c1eb7..5b5f30244e 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -28,6 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +// Must include Winsock before windows.h (included by os_uwp.h) +#include "drivers/unix/net_socket_posix.h" + #include "os_uwp.h" #include "core/io/marshalls.h" @@ -38,11 +41,8 @@ #include "drivers/windows/dir_access_windows.h" #include "drivers/windows/file_access_windows.h" #include "drivers/windows/mutex_windows.h" -#include "drivers/windows/packet_peer_udp_winsock.h" #include "drivers/windows/rw_lock_windows.h" #include "drivers/windows/semaphore_windows.h" -#include "drivers/windows/stream_peer_tcp_winsock.h" -#include "drivers/windows/tcp_server_winsock.h" #include "main/main.h" #include "platform/windows/windows_terminal_logger.h" #include "servers/audio_server.h" @@ -151,9 +151,7 @@ void OSUWP::initialize_core() { DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_USERDATA); DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_FILESYSTEM); - TCPServerWinsock::make_default(); - StreamPeerTCPWinsock::make_default(); - PacketPeerUDPWinsock::make_default(); + NetSocketPosix::make_default(); // We need to know how often the clock is updated if (!QueryPerformanceFrequency((LARGE_INTEGER *)&ticks_per_second)) diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index ef6c4c21eb..6723210432 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -28,6 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +// Must include Winsock before windows.h (included by os_windows.h) +#include "drivers/unix/net_socket_posix.h" + #include "os_windows.h" #include "core/io/marshalls.h" @@ -37,11 +40,8 @@ #include "drivers/windows/dir_access_windows.h" #include "drivers/windows/file_access_windows.h" #include "drivers/windows/mutex_windows.h" -#include "drivers/windows/packet_peer_udp_winsock.h" #include "drivers/windows/rw_lock_windows.h" #include "drivers/windows/semaphore_windows.h" -#include "drivers/windows/stream_peer_tcp_winsock.h" -#include "drivers/windows/tcp_server_winsock.h" #include "drivers/windows/thread_windows.h" #include "joypad.h" #include "lang_table.h" @@ -219,9 +219,7 @@ void OS_Windows::initialize_core() { DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_USERDATA); DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_FILESYSTEM); - TCPServerWinsock::make_default(); - StreamPeerTCPWinsock::make_default(); - PacketPeerUDPWinsock::make_default(); + NetSocketPosix::make_default(); // We need to know how often the clock is updated if (!QueryPerformanceFrequency((LARGE_INTEGER *)&ticks_per_second)) @@ -1514,9 +1512,6 @@ void OS_Windows::finalize_core() { timeEndPeriod(1); memdelete(process_map); - - TCPServerWinsock::cleanup(); - StreamPeerTCPWinsock::cleanup(); } void OS_Windows::alert(const String &p_alert, const String &p_title) { diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index 20c9dd6290..b80a20ce40 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -744,12 +744,15 @@ void OS_X11::set_mouse_mode(MouseMode p_mode) { ERR_PRINT("NO GRAB"); } - center.x = current_videomode.width / 2; - center.y = current_videomode.height / 2; - XWarpPointer(x11_display, None, x11_window, - 0, 0, 0, 0, (int)center.x, (int)center.y); + if (mouse_mode == MOUSE_MODE_CAPTURED) { + center.x = current_videomode.width / 2; + center.y = current_videomode.height / 2; + + XWarpPointer(x11_display, None, x11_window, + 0, 0, 0, 0, (int)center.x, (int)center.y); - input->set_mouse_position(center); + input->set_mouse_position(center); + } } else { do_mouse_warp = false; } @@ -2067,6 +2070,10 @@ void OS_X11::process_xevents() { Point2i rel = pos - last_mouse_pos; + if (mouse_mode == MOUSE_MODE_CAPTURED) { + pos = Point2i(current_videomode.width / 2, current_videomode.height / 2); + } + Ref<InputEventMouseMotion> mm; mm.instance(); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 60d5c45846..f56cc897ca 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -556,7 +556,6 @@ void TextEdit::_notification(int p_what) { } break; case NOTIFICATION_RESIZED: { - cache.size = get_size(); _update_scrollbars(); update_wrap_at(); } break; @@ -593,6 +592,7 @@ void TextEdit::_notification(int p_what) { } } break; case NOTIFICATION_DRAW: { + Size2 size = get_size(); if ((!has_focus() && !menu->has_focus()) || !window_has_focus) { draw_caret = false; } @@ -634,17 +634,17 @@ void TextEdit::_notification(int p_what) { RID ci = get_canvas_item(); VisualServer::get_singleton()->canvas_item_set_clip(get_canvas_item(), true); int xmargin_beg = cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width; - int xmargin_end = cache.size.width - cache.style_normal->get_margin(MARGIN_RIGHT); + int xmargin_end = size.width - cache.style_normal->get_margin(MARGIN_RIGHT); //let's do it easy for now: - cache.style_normal->draw(ci, Rect2(Point2(), cache.size)); + cache.style_normal->draw(ci, Rect2(Point2(), size)); float readonly_alpha = 1.0; // used to set the input text color when in read-only mode if (readonly) { - cache.style_readonly->draw(ci, Rect2(Point2(), cache.size)); + cache.style_readonly->draw(ci, Rect2(Point2(), size)); readonly_alpha = .5; draw_caret = false; } if (has_focus()) - cache.style_focus->draw(ci, Rect2(Point2(), cache.size)); + cache.style_focus->draw(ci, Rect2(Point2(), size)); int ascent = cache.font->get_ascent(); @@ -1261,7 +1261,7 @@ void TextEdit::_notification(int p_what) { if (line_length_guideline) { int x = xmargin_beg + cache.font->get_char_size('0').width * line_length_guideline_col - cursor.x_ofs; if (x > xmargin_beg && x < xmargin_end) { - VisualServer::get_singleton()->canvas_item_add_line(ci, Point2(x, 0), Point2(x, cache.size.height), cache.line_length_guideline_color); + VisualServer::get_singleton()->canvas_item_add_line(ci, Point2(x, 0), Point2(x, size.height), cache.line_length_guideline_color); } } @@ -3625,7 +3625,7 @@ Size2 TextEdit::get_minimum_size() const { int TextEdit::get_visible_rows() const { - int total = cache.size.height; + int total = get_size().height; total -= cache.style_normal->get_minimum_size().height; if (h_scroll->is_visible_in_tree()) total -= h_scroll->get_size().height; @@ -3652,7 +3652,7 @@ int TextEdit::get_total_visible_rows() const { void TextEdit::update_wrap_at() { - wrap_at = cache.size.width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width - wrap_right_offset; + wrap_at = get_size().width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width - wrap_right_offset; update_cursor_wrap_offset(); text.clear_wrap_cache(); @@ -3686,7 +3686,7 @@ void TextEdit::adjust_viewport_to_cursor() { set_line_as_last_visible(cur_line, cur_wrap); } - int visible_width = cache.size.width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width; + int visible_width = get_size().width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width; if (v_scroll->is_visible_in_tree()) visible_width -= v_scroll->get_combined_minimum_size().width; visible_width -= 20; // give it a little more space @@ -3717,7 +3717,7 @@ void TextEdit::center_viewport_to_cursor() { unfold_line(cursor.line); set_line_as_center_visible(cursor.line, get_cursor_wrap_index()); - int visible_width = cache.size.width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width; + int visible_width = get_size().width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width; if (v_scroll->is_visible_in_tree()) visible_width -= v_scroll->get_combined_minimum_size().width; visible_width -= 20; // give it a little more space @@ -4174,7 +4174,7 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const { } } - return CURSOR_IBEAM; + return get_default_cursor_shape(); } void TextEdit::set_text(String p_text) { @@ -5562,7 +5562,7 @@ int TextEdit::get_last_visible_line_wrap_index() const { double TextEdit::get_visible_rows_offset() const { - double total = cache.size.height; + double total = get_size().height; total -= cache.style_normal->get_minimum_size().height; if (h_scroll->is_visible_in_tree()) total -= h_scroll->get_size().height; @@ -6249,7 +6249,6 @@ TextEdit::TextEdit() { set_focus_mode(FOCUS_ALL); syntax_highlighter = NULL; _update_caches(); - cache.size = Size2(1, 1); cache.row_height = 1; cache.line_spacing = 1; cache.line_number_w = 1; @@ -6257,6 +6256,7 @@ TextEdit::TextEdit() { breakpoint_gutter_width = 0; cache.fold_gutter_width = 0; fold_gutter_width = 0; + set_default_cursor_shape(CURSOR_IBEAM); indent_size = 4; text.set_indent_size(indent_size); diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 697dc3a5e0..f0c18ad047 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -193,7 +193,6 @@ private: int line_number_w; int breakpoint_gutter_width; int fold_gutter_width; - Size2 size; } cache; Map<int, int> color_region_cache; diff --git a/thirdparty/enet/godot.cpp b/thirdparty/enet/godot.cpp index 7813b70286..6ba7cf0000 100644 --- a/thirdparty/enet/godot.cpp +++ b/thirdparty/enet/godot.cpp @@ -108,7 +108,7 @@ int enet_socket_bind(ENetSocket socket, const ENetAddress *address) { ENetSocket enet_socket_create(ENetSocketType type) { - PacketPeerUDP *socket = PacketPeerUDP::create(); + PacketPeerUDP *socket = memnew(PacketPeerUDP); socket->set_blocking_mode(false); return socket; @@ -151,7 +151,7 @@ int enet_socket_send(ENetSocket socket, const ENetAddress *address, const ENetBu err = sock->put_packet((const uint8_t *)&w[0], size); if (err != OK) { - if (err == ERR_UNAVAILABLE) { // blocking call + if (err == ERR_BUSY) { // Blocking call return 0; } @@ -168,8 +168,9 @@ int enet_socket_receive(ENetSocket socket, ENetAddress *address, ENetBuffer *buf PacketPeerUDP *sock = (PacketPeerUDP *)socket; - if (sock->get_available_packet_count() == 0) { - return 0; + int pc = sock->get_available_packet_count(); + if (pc < 1) { + return pc; } const uint8_t *buffer; |