Merge pull request #107954 from stuartcarnie/unix_domain_socket_support

Add Core UNIX domain socket support
This commit is contained in:
Thaddeus Crews 2025-09-30 18:35:08 -05:00
commit 6b22951162
No known key found for this signature in database
GPG key ID: 8C6E5FEB5FC03CCC
39 changed files with 1791 additions and 529 deletions

View file

@ -54,21 +54,61 @@ public:
TYPE_UDP,
};
virtual Error open(Type p_type, IP::Type &ip_type) = 0;
enum class Family {
NONE,
INET,
UNIX,
};
class Address {
Family _family = Family::NONE;
CharString _path;
IPAddress _ip;
uint16_t _port = 0;
public:
_FORCE_INLINE_ Family get_family() const { return _family; }
_FORCE_INLINE_ bool is_inet() const { return _family == Family::INET; }
_FORCE_INLINE_ bool is_unix() const { return _family == Family::UNIX; }
_FORCE_INLINE_ bool is_valid() const { return is_inet() || is_unix(); }
_FORCE_INLINE_ const IPAddress &ip() const { return _ip; }
_FORCE_INLINE_ const uint16_t &port() const { return _port; }
_FORCE_INLINE_ const CharString &get_path() const { return _path; }
Address() {}
Address(const IPAddress &p_addr, uint16_t p_port) :
_family(Family::INET) {
_ip = p_addr;
_port = p_port;
}
Address(const String &p_path) :
_family(Family::UNIX), _path(p_path.utf8()) {
}
Address(const CharString &p_path) :
_family(Family::UNIX), _path(p_path) {
}
};
virtual Error open(Family p_family, Type p_type, IP::Type &r_ip_type) = 0;
virtual void close() = 0;
virtual Error bind(IPAddress p_addr, uint16_t p_port) = 0;
virtual Error bind(Address p_addr) = 0;
virtual Error listen(int p_max_pending) = 0;
virtual Error connect_to_host(IPAddress p_addr, uint16_t p_port) = 0;
virtual Error connect_to_host(Address p_addr) = 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, IPAddress &r_ip, uint16_t &r_port, bool p_peek = false) = 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, IPAddress p_ip, uint16_t p_port) = 0;
virtual Ref<NetSocket> accept(IPAddress &r_ip, uint16_t &r_port) = 0;
virtual Ref<NetSocket> accept(Address &r_addr) = 0;
virtual bool is_open() const = 0;
virtual int get_available_bytes() const = 0;
virtual Error get_socket_address(IPAddress *r_ip, uint16_t *r_port) const = 0;
virtual Error get_socket_address(Address *r_addr) const = 0;
virtual Error set_broadcasting_enabled(bool p_enabled) = 0; // Returns OK if the socket option has been set successfully.
virtual void set_blocking_enabled(bool p_enabled) = 0;

View file

@ -52,7 +52,7 @@ Error PacketPeerUDP::join_multicast_group(IPAddress p_multi_address, const Strin
if (!_sock->is_open()) {
IP::Type ip_type = p_multi_address.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6;
Error err = _sock->open(NetSocket::TYPE_UDP, ip_type);
Error err = _sock->open(NetSocket::Family::INET, NetSocket::TYPE_UDP, ip_type);
ERR_FAIL_COND_V(err != OK, err);
_sock->set_blocking_enabled(false);
_sock->set_broadcasting_enabled(broadcast);
@ -141,7 +141,7 @@ Error PacketPeerUDP::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
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 = _sock->open(NetSocket::Family::INET, NetSocket::TYPE_UDP, ip_type);
ERR_FAIL_COND_V(err != OK, err);
_sock->set_blocking_enabled(false);
_sock->set_broadcasting_enabled(broadcast);
@ -186,7 +186,7 @@ Error PacketPeerUDP::bind(int p_port, const IPAddress &p_bind_address, int p_rec
ip_type = p_bind_address.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6;
}
err = _sock->open(NetSocket::TYPE_UDP, ip_type);
err = _sock->open(NetSocket::Family::INET, NetSocket::TYPE_UDP, ip_type);
if (err != OK) {
return ERR_CANT_CREATE;
@ -194,7 +194,8 @@ Error PacketPeerUDP::bind(int p_port, const IPAddress &p_bind_address, int p_rec
_sock->set_blocking_enabled(false);
_sock->set_broadcasting_enabled(broadcast);
err = _sock->bind(p_bind_address, p_port);
NetSocket::Address addr(p_bind_address, p_port);
err = _sock->bind(addr);
if (err != OK) {
_sock->close();
@ -231,12 +232,13 @@ Error PacketPeerUDP::connect_to_host(const IPAddress &p_host, int p_port) {
if (!_sock->is_open()) {
IP::Type ip_type = p_host.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6;
err = _sock->open(NetSocket::TYPE_UDP, ip_type);
err = _sock->open(NetSocket::Family::INET, NetSocket::TYPE_UDP, ip_type);
ERR_FAIL_COND_V(err != OK, ERR_CANT_OPEN);
_sock->set_blocking_enabled(false);
}
err = _sock->connect_to_host(p_host, p_port);
NetSocket::Address addr(p_host, p_port);
err = _sock->connect_to_host(addr);
// I see no reason why we should get ERR_BUSY (wouldblock/eagain) here.
// This is UDP, so connect is only used to tell the OS to which socket
@ -345,9 +347,9 @@ int PacketPeerUDP::get_packet_port() const {
}
int PacketPeerUDP::get_local_port() const {
uint16_t local_port;
_sock->get_socket_address(nullptr, &local_port);
return local_port;
NetSocket::Address addr;
_sock->get_socket_address(&addr);
return addr.port();
}
void PacketPeerUDP::set_dest_address(const IPAddress &p_address, int p_port) {

90
core/io/socket_server.cpp Normal file
View file

@ -0,0 +1,90 @@
/**************************************************************************/
/* socket_server.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "socket_server.h"
void SocketServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_connection_available"), &SocketServer::is_connection_available);
ClassDB::bind_method(D_METHOD("is_listening"), &SocketServer::is_listening);
ClassDB::bind_method(D_METHOD("stop"), &SocketServer::stop);
ClassDB::bind_method(D_METHOD("take_socket_connection"), &SocketServer::take_socket_connection);
}
Error SocketServer::_listen(const NetSocket::Address &p_addr) {
DEV_ASSERT(_sock.is_valid());
DEV_ASSERT(_sock->is_open());
_sock->set_blocking_enabled(false);
Error err = _sock->bind(p_addr);
if (err != OK) {
_sock->close();
return ERR_ALREADY_IN_USE;
}
err = _sock->listen(MAX_PENDING_CONNECTIONS);
if (err != OK) {
_sock->close();
return FAILED;
}
return OK;
}
bool SocketServer::is_listening() const {
ERR_FAIL_COND_V(_sock.is_null(), false);
return _sock->is_open();
}
bool SocketServer::is_connection_available() const {
ERR_FAIL_COND_V(_sock.is_null(), false);
if (!_sock->is_open()) {
return false;
}
Error err = _sock->poll(NetSocket::POLL_TYPE_IN, 0);
return (err == OK);
}
void SocketServer::stop() {
if (_sock.is_valid()) {
_sock->close();
}
}
SocketServer::SocketServer() :
_sock(NetSocket::create()) {
}
SocketServer::~SocketServer() {
stop();
}

77
core/io/socket_server.h Normal file
View file

@ -0,0 +1,77 @@
/**************************************************************************/
/* socket_server.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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. */
/**************************************************************************/
#pragma once
#include "core/io/net_socket.h"
#include "core/io/stream_peer_socket.h"
class SocketServer : public RefCounted {
GDCLASS(SocketServer, RefCounted);
protected:
enum {
MAX_PENDING_CONNECTIONS = 8,
};
Ref<NetSocket> _sock;
static void _bind_methods();
Error _listen(const NetSocket::Address &p_addr);
template <typename T>
Ref<T> _take_connection() {
Ref<T> conn;
if (!is_connection_available()) {
return conn;
}
Ref<NetSocket> ns;
NetSocket::Address addr;
ns = _sock->accept(addr);
if (ns.is_null()) {
return conn;
}
conn.instantiate();
conn->accept_socket(ns, addr);
return conn;
}
public:
bool is_listening() const;
bool is_connection_available() const;
virtual Ref<StreamPeerSocket> take_socket_connection() = 0;
void stop(); // Stop listening
SocketServer();
~SocketServer();
};

View file

@ -0,0 +1,52 @@
/**************************************************************************/
/* stream_peer_socket.compat.inc */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 DISABLE_DEPRECATED
namespace compat::StreamPeerTCP {
enum class Status {
STATUS_NONE = StreamPeerSocket::STATUS_NONE,
STATUS_CONNECTING = StreamPeerSocket::STATUS_CONNECTING,
STATUS_CONNECTED = StreamPeerSocket::STATUS_CONNECTED,
STATUS_ERROR = StreamPeerSocket::STATUS_ERROR,
};
}
VARIANT_ENUM_CAST(compat::StreamPeerTCP::Status);
compat::StreamPeerTCP::Status StreamPeerSocket::_get_status_compat_107954() const {
return (compat::StreamPeerTCP::Status)get_status();
}
void StreamPeerSocket::_bind_compatibility_methods() {
ClassDB::bind_compatibility_method(D_METHOD("get_status"), &StreamPeerSocket::_get_status_compat_107954);
}
#endif

View file

@ -0,0 +1,236 @@
/**************************************************************************/
/* stream_peer_socket.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "stream_peer_socket.h"
#include "stream_peer_socket.compat.inc"
Error StreamPeerSocket::poll() {
if (status == STATUS_CONNECTED) {
Error err;
err = _sock->poll(NetSocket::POLL_TYPE_IN, 0);
if (err == OK) {
// FIN received
if (_sock->get_available_bytes() == 0) {
disconnect_from_host();
return OK;
}
}
// Also poll write
err = _sock->poll(NetSocket::POLL_TYPE_IN_OUT, 0);
if (err != OK && err != ERR_BUSY) {
// Got an error
disconnect_from_host();
status = STATUS_ERROR;
return err;
}
return OK;
} else if (status != STATUS_CONNECTING) {
return OK;
}
Error err = _sock->connect_to_host(peer_address);
if (err == OK) {
status = STATUS_CONNECTED;
return OK;
} else if (err == ERR_BUSY) {
// Check for connect timeout
if (OS::get_singleton()->get_ticks_msec() > timeout) {
disconnect_from_host();
status = STATUS_ERROR;
return ERR_CONNECTION_ERROR;
}
// Still trying to connect
return OK;
}
disconnect_from_host();
status = STATUS_ERROR;
return ERR_CONNECTION_ERROR;
}
Error StreamPeerSocket::write(const uint8_t *p_data, int p_bytes, int &r_sent, bool p_block) {
ERR_FAIL_COND_V(_sock.is_null(), ERR_UNAVAILABLE);
if (status != STATUS_CONNECTED) {
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 StreamPeerSocket::read(uint8_t *p_buffer, int p_bytes, int &r_received, bool p_block) {
if (status != STATUS_CONNECTED) {
return FAILED;
}
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) {
disconnect_from_host();
r_received = total_read;
return ERR_FILE_EOF;
} else {
to_read -= read;
total_read += read;
if (!p_block) {
r_received = total_read;
return OK;
}
}
}
r_received = total_read;
return OK;
}
StreamPeerSocket::Status StreamPeerSocket::get_status() const {
return status;
}
void StreamPeerSocket::disconnect_from_host() {
if (_sock.is_valid() && _sock->is_open()) {
_sock->close();
}
timeout = 0;
status = STATUS_NONE;
peer_address = NetSocket::Address();
}
Error StreamPeerSocket::wait(NetSocket::PollType p_type, int p_timeout) {
ERR_FAIL_COND_V(_sock.is_null() || !_sock->is_open(), ERR_UNAVAILABLE);
return _sock->poll(p_type, p_timeout);
}
Error StreamPeerSocket::put_data(const uint8_t *p_data, int p_bytes) {
int total;
return write(p_data, p_bytes, total, true);
}
Error StreamPeerSocket::put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) {
return write(p_data, p_bytes, r_sent, false);
}
Error StreamPeerSocket::get_data(uint8_t *p_buffer, int p_bytes) {
int total;
return read(p_buffer, p_bytes, total, true);
}
Error StreamPeerSocket::get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) {
return read(p_buffer, p_bytes, r_received, false);
}
int StreamPeerSocket::get_available_bytes() const {
ERR_FAIL_COND_V(_sock.is_null(), -1);
return _sock->get_available_bytes();
}
void StreamPeerSocket::_bind_methods() {
ClassDB::bind_method(D_METHOD("poll"), &StreamPeerSocket::poll);
ClassDB::bind_method(D_METHOD("get_status"), &StreamPeerSocket::get_status);
ClassDB::bind_method(D_METHOD("disconnect_from_host"), &StreamPeerSocket::disconnect_from_host);
BIND_ENUM_CONSTANT(STATUS_NONE);
BIND_ENUM_CONSTANT(STATUS_CONNECTING);
BIND_ENUM_CONSTANT(STATUS_CONNECTED);
BIND_ENUM_CONSTANT(STATUS_ERROR);
}
StreamPeerSocket::StreamPeerSocket() :
_sock(NetSocket::create()) {
}
StreamPeerSocket::~StreamPeerSocket() {
disconnect_from_host();
}

View file

@ -0,0 +1,93 @@
/**************************************************************************/
/* stream_peer_socket.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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. */
/**************************************************************************/
#pragma once
#include "core/io/net_socket.h"
#include "core/io/stream_peer.h"
#ifndef DISABLE_DEPRECATED
namespace compat::StreamPeerTCP {
enum class Status;
} //namespace compat::StreamPeerTCP
#endif
class StreamPeerSocket : public StreamPeer {
GDCLASS(StreamPeerSocket, StreamPeer);
public:
enum Status {
STATUS_NONE,
STATUS_CONNECTING,
STATUS_CONNECTED,
STATUS_ERROR,
};
protected:
#ifndef DISABLE_DEPRECATED
compat::StreamPeerTCP::Status _get_status_compat_107954() const;
static void _bind_compatibility_methods();
#endif
Ref<NetSocket> _sock;
uint64_t timeout = 0;
Status status = STATUS_NONE;
NetSocket::Address peer_address;
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 void accept_socket(Ref<NetSocket> p_sock, const NetSocket::Address &p_addr) = 0;
void disconnect_from_host();
int get_available_bytes() const override;
Status get_status() const;
// Poll socket updating its state.
Error poll();
// Wait or check for writable, readable.
Error wait(NetSocket::PollType p_type, int p_timeout = 0);
// Read/Write from StreamPeer
Error put_data(const uint8_t *p_data, int p_bytes) override;
Error put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) override;
Error get_data(uint8_t *p_buffer, int p_bytes) override;
Error get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) override;
StreamPeerSocket();
virtual ~StreamPeerSocket();
};
VARIANT_ENUM_CAST(StreamPeerSocket::Status);

View file

@ -32,60 +32,14 @@
#include "core/config/project_settings.h"
Error StreamPeerTCP::poll() {
if (status == STATUS_CONNECTED) {
Error err;
err = _sock->poll(NetSocket::POLL_TYPE_IN, 0);
if (err == OK) {
// FIN received
if (_sock->get_available_bytes() == 0) {
disconnect_from_host();
return OK;
}
}
// Also poll write
err = _sock->poll(NetSocket::POLL_TYPE_IN_OUT, 0);
if (err != OK && err != ERR_BUSY) {
// Got an error
disconnect_from_host();
status = STATUS_ERROR;
return err;
}
return OK;
} else if (status != STATUS_CONNECTING) {
return OK;
}
Error err = _sock->connect_to_host(peer_host, peer_port);
if (err == OK) {
status = STATUS_CONNECTED;
return OK;
} else if (err == ERR_BUSY) {
// Check for connect timeout
if (OS::get_singleton()->get_ticks_msec() > timeout) {
disconnect_from_host();
status = STATUS_ERROR;
return ERR_CONNECTION_ERROR;
}
// Still trying to connect
return OK;
}
disconnect_from_host();
status = STATUS_ERROR;
return ERR_CONNECTION_ERROR;
}
void StreamPeerTCP::accept_socket(Ref<NetSocket> p_sock, IPAddress p_host, uint16_t p_port) {
void StreamPeerTCP::accept_socket(Ref<NetSocket> p_sock, const NetSocket::Address &p_addr) {
_sock = p_sock;
_sock->set_blocking_enabled(false);
timeout = OS::get_singleton()->get_ticks_msec() + (((uint64_t)GLOBAL_GET("network/limits/tcp/connect_timeout_seconds")) * 1000);
status = STATUS_CONNECTED;
peer_host = p_host;
peer_port = p_port;
peer_address = p_addr;
}
Error StreamPeerTCP::bind(int p_port, const IPAddress &p_host) {
@ -97,12 +51,13 @@ Error StreamPeerTCP::bind(int p_port, const IPAddress &p_host) {
if (p_host.is_wildcard()) {
ip_type = IP::TYPE_ANY;
}
Error err = _sock->open(NetSocket::TYPE_TCP, ip_type);
Error err = _sock->open(NetSocket::Family::INET, NetSocket::TYPE_TCP, ip_type);
if (err != OK) {
return err;
}
_sock->set_blocking_enabled(false);
return _sock->bind(p_host, p_port);
NetSocket::Address addr(p_host, p_port);
return _sock->bind(addr);
}
Error StreamPeerTCP::connect_to_host(const IPAddress &p_host, int p_port) {
@ -113,7 +68,7 @@ Error StreamPeerTCP::connect_to_host(const IPAddress &p_host, int p_port) {
if (!_sock->is_open()) {
IP::Type ip_type = p_host.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6;
Error err = _sock->open(NetSocket::TYPE_TCP, ip_type);
Error err = _sock->open(NetSocket::Family::INET, NetSocket::TYPE_TCP, ip_type);
if (err != OK) {
return err;
}
@ -121,7 +76,9 @@ Error StreamPeerTCP::connect_to_host(const IPAddress &p_host, int p_port) {
}
timeout = OS::get_singleton()->get_ticks_msec() + (((uint64_t)GLOBAL_GET("network/limits/tcp/connect_timeout_seconds")) * 1000);
Error err = _sock->connect_to_host(p_host, p_port);
NetSocket::Address addr(p_host, p_port);
Error err = _sock->connect_to_host(addr);
if (err == OK) {
status = STATUS_CONNECTED;
@ -133,106 +90,7 @@ Error StreamPeerTCP::connect_to_host(const IPAddress &p_host, int p_port) {
return FAILED;
}
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_null(), ERR_UNAVAILABLE);
if (status != STATUS_CONNECTED) {
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 (status != STATUS_CONNECTED) {
return FAILED;
}
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) {
disconnect_from_host();
r_received = total_read;
return ERR_FILE_EOF;
} else {
to_read -= read;
total_read += read;
if (!p_block) {
r_received = total_read;
return OK;
}
}
}
r_received = total_read;
peer_address = addr;
return OK;
}
@ -242,61 +100,18 @@ void StreamPeerTCP::set_no_delay(bool p_enabled) {
_sock->set_tcp_no_delay_enabled(p_enabled);
}
StreamPeerTCP::Status StreamPeerTCP::get_status() const {
return status;
}
void StreamPeerTCP::disconnect_from_host() {
if (_sock.is_valid() && _sock->is_open()) {
_sock->close();
}
timeout = 0;
status = STATUS_NONE;
peer_host = IPAddress();
peer_port = 0;
}
Error StreamPeerTCP::wait(NetSocket::PollType p_type, int p_timeout) {
ERR_FAIL_COND_V(_sock.is_null() || !_sock->is_open(), ERR_UNAVAILABLE);
return _sock->poll(p_type, p_timeout);
}
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_null(), -1);
return _sock->get_available_bytes();
}
IPAddress StreamPeerTCP::get_connected_host() const {
return peer_host;
return peer_address.ip();
}
int StreamPeerTCP::get_connected_port() const {
return peer_port;
return peer_address.port();
}
int StreamPeerTCP::get_local_port() const {
uint16_t local_port;
_sock->get_socket_address(nullptr, &local_port);
return local_port;
NetSocket::Address addr;
_sock->get_socket_address(&addr);
return addr.port();
}
Error StreamPeerTCP::_connect(const String &p_address, int p_port) {
@ -316,24 +131,8 @@ Error StreamPeerTCP::_connect(const String &p_address, int p_port) {
void StreamPeerTCP::_bind_methods() {
ClassDB::bind_method(D_METHOD("bind", "port", "host"), &StreamPeerTCP::bind, DEFVAL("*"));
ClassDB::bind_method(D_METHOD("connect_to_host", "host", "port"), &StreamPeerTCP::_connect);
ClassDB::bind_method(D_METHOD("poll"), &StreamPeerTCP::poll);
ClassDB::bind_method(D_METHOD("get_status"), &StreamPeerTCP::get_status);
ClassDB::bind_method(D_METHOD("get_connected_host"), &StreamPeerTCP::get_connected_host);
ClassDB::bind_method(D_METHOD("get_connected_port"), &StreamPeerTCP::get_connected_port);
ClassDB::bind_method(D_METHOD("get_local_port"), &StreamPeerTCP::get_local_port);
ClassDB::bind_method(D_METHOD("disconnect_from_host"), &StreamPeerTCP::disconnect_from_host);
ClassDB::bind_method(D_METHOD("set_no_delay", "enabled"), &StreamPeerTCP::set_no_delay);
BIND_ENUM_CONSTANT(STATUS_NONE);
BIND_ENUM_CONSTANT(STATUS_CONNECTING);
BIND_ENUM_CONSTANT(STATUS_CONNECTED);
BIND_ENUM_CONSTANT(STATUS_ERROR);
}
StreamPeerTCP::StreamPeerTCP() :
_sock(Ref<NetSocket>(NetSocket::create())) {
}
StreamPeerTCP::~StreamPeerTCP() {
disconnect_from_host();
}

View file

@ -32,62 +32,24 @@
#include "core/io/ip.h"
#include "core/io/ip_address.h"
#include "core/io/net_socket.h"
#include "core/io/stream_peer.h"
#include "core/io/stream_peer_socket.h"
class StreamPeerTCP : public StreamPeer {
GDCLASS(StreamPeerTCP, StreamPeer);
public:
enum Status {
STATUS_NONE,
STATUS_CONNECTING,
STATUS_CONNECTED,
STATUS_ERROR,
};
class StreamPeerTCP : public StreamPeerSocket {
GDCLASS(StreamPeerTCP, StreamPeerSocket);
protected:
Ref<NetSocket> _sock;
uint64_t timeout = 0;
Status status = STATUS_NONE;
IPAddress peer_host;
uint16_t peer_port = 0;
Error _connect(const String &p_address, int p_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 void _bind_methods();
public:
void accept_socket(Ref<NetSocket> p_sock, IPAddress p_host, uint16_t p_port);
void accept_socket(Ref<NetSocket> p_sock, const NetSocket::Address &p_addr) override;
Error bind(int p_port, const IPAddress &p_host);
Error connect_to_host(const IPAddress &p_host, int p_port);
IPAddress get_connected_host() const;
int get_connected_port() const;
int get_local_port() const;
void disconnect_from_host();
int get_available_bytes() const override;
Status get_status() const;
void set_no_delay(bool p_enabled);
// Poll socket updating its state.
Error poll();
// Wait or check for writable, readable.
Error wait(NetSocket::PollType p_type, int p_timeout = 0);
// Read/Write from StreamPeer
Error put_data(const uint8_t *p_data, int p_bytes) override;
Error put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) override;
Error get_data(uint8_t *p_buffer, int p_bytes) override;
Error get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) override;
StreamPeerTCP();
~StreamPeerTCP();
};
VARIANT_ENUM_CAST(StreamPeerTCP::Status);

View file

@ -0,0 +1,99 @@
/**************************************************************************/
/* stream_peer_uds.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "stream_peer_uds.h"
#include "core/config/project_settings.h"
void StreamPeerUDS::_bind_methods() {
ClassDB::bind_method(D_METHOD("bind", "path"), &StreamPeerUDS::bind);
ClassDB::bind_method(D_METHOD("connect_to_host", "path"), &StreamPeerUDS::connect_to_host);
ClassDB::bind_method(D_METHOD("get_connected_path"), &StreamPeerUDS::get_connected_path);
}
void StreamPeerUDS::accept_socket(Ref<NetSocket> p_sock, const NetSocket::Address &p_addr) {
_sock = p_sock;
_sock->set_blocking_enabled(false);
timeout = OS::get_singleton()->get_ticks_msec() + (((uint64_t)GLOBAL_GET("network/limits/unix/connect_timeout_seconds")) * 1000);
status = STATUS_CONNECTED;
}
Error StreamPeerUDS::bind(const String &p_path) {
ERR_FAIL_COND_V(_sock.is_null(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(_sock->is_open(), ERR_ALREADY_IN_USE);
IP::Type ip_type = IP::TYPE_NONE;
Error err = _sock->open(NetSocket::Family::UNIX, NetSocket::TYPE_NONE, ip_type);
if (err != OK) {
return err;
}
_sock->set_blocking_enabled(false);
NetSocket::Address addr(p_path);
return _sock->bind(addr);
}
Error StreamPeerUDS::connect_to_host(const String &p_path) {
ERR_FAIL_COND_V(_sock.is_null(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(_sock->is_open(), ERR_ALREADY_IN_USE);
ERR_FAIL_COND_V(p_path.is_empty(), ERR_INVALID_PARAMETER);
if (!_sock->is_open()) {
IP::Type ip_type = IP::TYPE_NONE;
Error err = _sock->open(NetSocket::Family::UNIX, NetSocket::TYPE_NONE, ip_type);
if (err != OK) {
return err;
}
_sock->set_blocking_enabled(false);
}
timeout = OS::get_singleton()->get_ticks_msec() + (((uint64_t)GLOBAL_GET("network/limits/unix/connect_timeout_seconds")) * 1000);
NetSocket::Address addr(p_path);
Error err = _sock->connect_to_host(addr);
if (err == OK) {
status = STATUS_CONNECTED;
} else if (err == ERR_BUSY) {
status = STATUS_CONNECTING;
} else {
ERR_PRINT("Connection to remote host failed!");
disconnect_from_host();
return FAILED;
}
peer_address = addr;
peer_path = p_path;
return OK;
}
const String StreamPeerUDS::get_connected_path() const {
return String(peer_address.get_path().get_data());
}

48
core/io/stream_peer_uds.h Normal file
View file

@ -0,0 +1,48 @@
/**************************************************************************/
/* stream_peer_uds.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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. */
/**************************************************************************/
#pragma once
#include "core/io/stream_peer_socket.h"
class StreamPeerUDS : public StreamPeerSocket {
GDCLASS(StreamPeerUDS, StreamPeerSocket);
protected:
String peer_path;
static void _bind_methods();
public:
void accept_socket(Ref<NetSocket> p_sock, const NetSocket::Address &p_addr) override;
Error bind(const String &p_path);
Error connect_to_host(const String &p_path);
const String get_connected_path() const;
};

View file

@ -32,11 +32,8 @@
void TCPServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("listen", "port", "bind_address"), &TCPServer::listen, DEFVAL("*"));
ClassDB::bind_method(D_METHOD("is_connection_available"), &TCPServer::is_connection_available);
ClassDB::bind_method(D_METHOD("is_listening"), &TCPServer::is_listening);
ClassDB::bind_method(D_METHOD("get_local_port"), &TCPServer::get_local_port);
ClassDB::bind_method(D_METHOD("take_connection"), &TCPServer::take_connection);
ClassDB::bind_method(D_METHOD("stop"), &TCPServer::stop);
}
Error TCPServer::listen(uint16_t p_port, const IPAddress &p_bind_address) {
@ -52,81 +49,21 @@ Error TCPServer::listen(uint16_t p_port, const IPAddress &p_bind_address) {
ip_type = p_bind_address.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6;
}
err = _sock->open(NetSocket::TYPE_TCP, ip_type);
err = _sock->open(NetSocket::Family::INET, 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;
}
err = _sock->listen(MAX_PENDING_CONNECTIONS);
if (err != OK) {
_sock->close();
return FAILED;
}
return OK;
return _listen(NetSocket::Address(p_bind_address, p_port));
}
int TCPServer::get_local_port() const {
uint16_t local_port;
_sock->get_socket_address(nullptr, &local_port);
return local_port;
}
bool TCPServer::is_listening() const {
ERR_FAIL_COND_V(_sock.is_null(), false);
return _sock->is_open();
}
bool TCPServer::is_connection_available() const {
ERR_FAIL_COND_V(_sock.is_null(), false);
if (!_sock->is_open()) {
return false;
}
Error err = _sock->poll(NetSocket::POLL_TYPE_IN, 0);
return (err == OK);
NetSocket::Address addr;
_sock->get_socket_address(&addr);
return addr.port();
}
Ref<StreamPeerTCP> TCPServer::take_connection() {
Ref<StreamPeerTCP> conn;
if (!is_connection_available()) {
return conn;
}
Ref<NetSocket> ns;
IPAddress ip;
uint16_t port = 0;
ns = _sock->accept(ip, port);
if (ns.is_null()) {
return conn;
}
conn.instantiate();
conn->accept_socket(ns, ip, port);
return conn;
}
void TCPServer::stop() {
if (_sock.is_valid()) {
_sock->close();
}
}
TCPServer::TCPServer() :
_sock(Ref<NetSocket>(NetSocket::create())) {
}
TCPServer::~TCPServer() {
stop();
return _take_connection<StreamPeerTCP>();
}

View file

@ -31,30 +31,18 @@
#pragma once
#include "core/io/ip.h"
#include "core/io/net_socket.h"
#include "core/io/stream_peer.h"
#include "core/io/socket_server.h"
#include "core/io/stream_peer_tcp.h"
class TCPServer : public RefCounted {
GDCLASS(TCPServer, RefCounted);
class TCPServer : public SocketServer {
GDCLASS(TCPServer, SocketServer);
protected:
enum {
MAX_PENDING_CONNECTIONS = 8
};
Ref<NetSocket> _sock;
static void _bind_methods();
public:
Error listen(uint16_t p_port, const IPAddress &p_bind_address = IPAddress("*"));
int get_local_port() const;
bool is_listening() const;
bool is_connection_available() const;
Ref<StreamPeerTCP> take_connection();
void stop(); // Stop listening
TCPServer();
~TCPServer();
Ref<StreamPeerSocket> take_socket_connection() override { return take_connection(); }
};

View file

@ -99,7 +99,7 @@ Error UDPServer::listen(uint16_t p_port, const IPAddress &p_bind_address) {
ip_type = p_bind_address.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6;
}
err = _sock->open(NetSocket::TYPE_UDP, ip_type);
err = _sock->open(NetSocket::Family::INET, NetSocket::TYPE_UDP, ip_type);
if (err != OK) {
return ERR_CANT_CREATE;
@ -107,7 +107,8 @@ Error UDPServer::listen(uint16_t p_port, const IPAddress &p_bind_address) {
_sock->set_blocking_enabled(false);
_sock->set_reuse_address_enabled(true);
err = _sock->bind(p_bind_address, p_port);
NetSocket::Address addr(p_bind_address, p_port);
err = _sock->bind(addr);
if (err != OK) {
stop();
@ -117,9 +118,9 @@ Error UDPServer::listen(uint16_t p_port, const IPAddress &p_bind_address) {
}
int UDPServer::get_local_port() const {
uint16_t local_port;
_sock->get_socket_address(nullptr, &local_port);
return local_port;
NetSocket::Address addr;
_sock->get_socket_address(&addr);
return addr.port();
}
bool UDPServer::is_listening() const {

52
core/io/uds_server.cpp Normal file
View file

@ -0,0 +1,52 @@
/**************************************************************************/
/* uds_server.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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 "uds_server.h"
void UDSServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("listen", "path"), &UDSServer::listen);
ClassDB::bind_method(D_METHOD("take_connection"), &UDSServer::take_connection);
}
Error UDSServer::listen(const String &p_path) {
ERR_FAIL_COND_V(_sock.is_null(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(_sock->is_open(), ERR_ALREADY_IN_USE);
ERR_FAIL_COND_V(p_path.is_empty(), ERR_INVALID_PARAMETER);
IP::Type ip_type = IP::TYPE_NONE;
Error err = _sock->open(NetSocket::Family::UNIX, NetSocket::TYPE_NONE, ip_type);
ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
return _listen(p_path);
}
Ref<StreamPeerUDS> UDSServer::take_connection() {
return _take_connection<StreamPeerUDS>();
}

46
core/io/uds_server.h Normal file
View file

@ -0,0 +1,46 @@
/**************************************************************************/
/* uds_server.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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. */
/**************************************************************************/
#pragma once
#include "core/io/socket_server.h"
#include "core/io/stream_peer_uds.h"
class UDSServer : public SocketServer {
GDCLASS(UDSServer, SocketServer);
protected:
static void _bind_methods();
public:
Error listen(const String &p_path);
Ref<StreamPeerUDS> take_connection();
Ref<StreamPeerSocket> take_socket_connection() override { return take_connection(); }
};