feat: updated engine version to 4.4-rc1
This commit is contained in:
parent
ee00efde1f
commit
21ba8e33af
5459 changed files with 1128836 additions and 198305 deletions
|
|
@ -1,4 +1,5 @@
|
|||
#!/usr/bin/env python
|
||||
from misc.utility.scons_hints import *
|
||||
|
||||
Import("env")
|
||||
|
||||
|
|
|
|||
|
|
@ -397,14 +397,30 @@ Error DirAccessUnix::rename(String p_path, String p_new_path) {
|
|||
}
|
||||
|
||||
p_path = fix_path(p_path);
|
||||
if (p_path.ends_with("/")) {
|
||||
p_path = p_path.left(-1);
|
||||
}
|
||||
|
||||
if (p_new_path.is_relative_path()) {
|
||||
p_new_path = get_current_dir().path_join(p_new_path);
|
||||
}
|
||||
|
||||
p_new_path = fix_path(p_new_path);
|
||||
if (p_new_path.ends_with("/")) {
|
||||
p_new_path = p_new_path.left(-1);
|
||||
}
|
||||
|
||||
return ::rename(p_path.utf8().get_data(), p_new_path.utf8().get_data()) == 0 ? OK : FAILED;
|
||||
int res = ::rename(p_path.utf8().get_data(), p_new_path.utf8().get_data());
|
||||
if (res != 0 && errno == EXDEV) { // Cross-device move, use copy and remove.
|
||||
Error err = OK;
|
||||
err = copy(p_path, p_new_path);
|
||||
if (err != OK) {
|
||||
return err;
|
||||
}
|
||||
return remove(p_path);
|
||||
} else {
|
||||
return (res == 0) ? OK : FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
Error DirAccessUnix::remove(String p_path) {
|
||||
|
|
@ -413,17 +429,28 @@ Error DirAccessUnix::remove(String p_path) {
|
|||
}
|
||||
|
||||
p_path = fix_path(p_path);
|
||||
if (p_path.ends_with("/")) {
|
||||
p_path = p_path.left(-1);
|
||||
}
|
||||
|
||||
struct stat flags = {};
|
||||
if ((stat(p_path.utf8().get_data(), &flags) != 0)) {
|
||||
if ((lstat(p_path.utf8().get_data(), &flags) != 0)) {
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
int err;
|
||||
if (S_ISDIR(flags.st_mode) && !is_link(p_path)) {
|
||||
return ::rmdir(p_path.utf8().get_data()) == 0 ? OK : FAILED;
|
||||
err = ::rmdir(p_path.utf8().get_data());
|
||||
} else {
|
||||
return ::unlink(p_path.utf8().get_data()) == 0 ? OK : FAILED;
|
||||
err = ::unlink(p_path.utf8().get_data());
|
||||
}
|
||||
if (err != 0) {
|
||||
return FAILED;
|
||||
}
|
||||
if (remove_notification_func != nullptr) {
|
||||
remove_notification_func(p_path);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
bool DirAccessUnix::is_link(String p_file) {
|
||||
|
|
@ -432,6 +459,9 @@ bool DirAccessUnix::is_link(String p_file) {
|
|||
}
|
||||
|
||||
p_file = fix_path(p_file);
|
||||
if (p_file.ends_with("/")) {
|
||||
p_file = p_file.left(-1);
|
||||
}
|
||||
|
||||
struct stat flags = {};
|
||||
if ((lstat(p_file.utf8().get_data(), &flags) != 0)) {
|
||||
|
|
@ -447,6 +477,9 @@ String DirAccessUnix::read_link(String p_file) {
|
|||
}
|
||||
|
||||
p_file = fix_path(p_file);
|
||||
if (p_file.ends_with("/")) {
|
||||
p_file = p_file.left(-1);
|
||||
}
|
||||
|
||||
char buf[256];
|
||||
memset(buf, 0, 256);
|
||||
|
|
@ -527,6 +560,8 @@ DirAccessUnix::DirAccessUnix() {
|
|||
change_dir(current_dir);
|
||||
}
|
||||
|
||||
DirAccessUnix::RemoveNotificationFunc DirAccessUnix::remove_notification_func = nullptr;
|
||||
|
||||
DirAccessUnix::~DirAccessUnix() {
|
||||
list_dir_end();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,9 @@ protected:
|
|||
virtual bool is_hidden(const String &p_name);
|
||||
|
||||
public:
|
||||
typedef void (*RemoveNotificationFunc)(const String &p_file);
|
||||
static RemoveNotificationFunc remove_notification_func;
|
||||
|
||||
virtual Error list_dir_begin() override; ///< This starts dir listing
|
||||
virtual String get_next() override;
|
||||
virtual bool current_is_dir() const override;
|
||||
|
|
|
|||
|
|
@ -41,10 +41,23 @@
|
|||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void FileAccessUnix::check_errors() const {
|
||||
#if defined(TOOLS_ENABLED)
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
void FileAccessUnix::check_errors(bool p_write) const {
|
||||
ERR_FAIL_NULL_MSG(f, "File must be opened before use.");
|
||||
|
||||
if (feof(f)) {
|
||||
last_error = OK;
|
||||
if (ferror(f)) {
|
||||
if (p_write) {
|
||||
last_error = ERR_FILE_CANT_WRITE;
|
||||
} else {
|
||||
last_error = ERR_FILE_CANT_READ;
|
||||
}
|
||||
}
|
||||
if (!p_write && feof(f)) {
|
||||
last_error = ERR_FILE_EOF;
|
||||
}
|
||||
}
|
||||
|
|
@ -87,6 +100,22 @@ Error FileAccessUnix::open_internal(const String &p_path, int p_mode_flags) {
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(TOOLS_ENABLED)
|
||||
if (p_mode_flags & READ) {
|
||||
String real_path = get_real_path();
|
||||
if (real_path != path) {
|
||||
// Don't warn on symlinks, since they can be used to simply share addons on multiple projects.
|
||||
if (real_path.to_lower() == path.to_lower()) {
|
||||
// The File system is case insensitive, but other platforms can be sensitive to it
|
||||
// To ease cross-platform development, we issue a warning if users try to access
|
||||
// a file using the wrong case (which *works* on Windows and macOS, but won't on other
|
||||
// platforms).
|
||||
WARN_PRINT(vformat("Case mismatch opening requested file '%s', stored as '%s' in the filesystem. This file will not open when exported to other case-sensitive platforms.", path, real_path));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (is_backup_save_enabled() && (p_mode_flags == WRITE)) {
|
||||
save_path = path;
|
||||
// Create a temporary file in the same directory as the target file.
|
||||
|
|
@ -97,7 +126,7 @@ Error FileAccessUnix::open_internal(const String &p_path, int p_mode_flags) {
|
|||
last_error = ERR_FILE_CANT_OPEN;
|
||||
return last_error;
|
||||
}
|
||||
fchmod(fd, 0666);
|
||||
fchmod(fd, 0644);
|
||||
path = String::utf8(cs.ptr());
|
||||
|
||||
f = fdopen(fd, mode_string);
|
||||
|
|
@ -173,10 +202,29 @@ String FileAccessUnix::get_path_absolute() const {
|
|||
return path;
|
||||
}
|
||||
|
||||
#if defined(TOOLS_ENABLED)
|
||||
String FileAccessUnix::get_real_path() const {
|
||||
char *resolved_path = ::realpath(path.utf8().get_data(), nullptr);
|
||||
|
||||
if (!resolved_path) {
|
||||
return path;
|
||||
}
|
||||
|
||||
String result;
|
||||
Error parse_ok = result.parse_utf8(resolved_path);
|
||||
::free(resolved_path);
|
||||
|
||||
if (parse_ok != OK) {
|
||||
return path;
|
||||
}
|
||||
|
||||
return result.simplify_path();
|
||||
}
|
||||
#endif
|
||||
|
||||
void FileAccessUnix::seek(uint64_t p_position) {
|
||||
ERR_FAIL_NULL_MSG(f, "File must be opened before use.");
|
||||
|
||||
last_error = OK;
|
||||
if (fseeko(f, p_position, SEEK_SET)) {
|
||||
check_errors();
|
||||
}
|
||||
|
|
@ -215,70 +263,16 @@ uint64_t FileAccessUnix::get_length() const {
|
|||
}
|
||||
|
||||
bool FileAccessUnix::eof_reached() const {
|
||||
return last_error == ERR_FILE_EOF;
|
||||
}
|
||||
|
||||
uint8_t FileAccessUnix::get_8() const {
|
||||
ERR_FAIL_NULL_V_MSG(f, 0, "File must be opened before use.");
|
||||
uint8_t b;
|
||||
if (fread(&b, 1, 1, f) == 0) {
|
||||
check_errors();
|
||||
b = '\0';
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
uint16_t FileAccessUnix::get_16() const {
|
||||
ERR_FAIL_NULL_V_MSG(f, 0, "File must be opened before use.");
|
||||
|
||||
uint16_t b = 0;
|
||||
if (fread(&b, 1, 2, f) != 2) {
|
||||
check_errors();
|
||||
}
|
||||
|
||||
if (big_endian) {
|
||||
b = BSWAP16(b);
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
uint32_t FileAccessUnix::get_32() const {
|
||||
ERR_FAIL_NULL_V_MSG(f, 0, "File must be opened before use.");
|
||||
|
||||
uint32_t b = 0;
|
||||
if (fread(&b, 1, 4, f) != 4) {
|
||||
check_errors();
|
||||
}
|
||||
|
||||
if (big_endian) {
|
||||
b = BSWAP32(b);
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
uint64_t FileAccessUnix::get_64() const {
|
||||
ERR_FAIL_NULL_V_MSG(f, 0, "File must be opened before use.");
|
||||
|
||||
uint64_t b = 0;
|
||||
if (fread(&b, 1, 8, f) != 8) {
|
||||
check_errors();
|
||||
}
|
||||
|
||||
if (big_endian) {
|
||||
b = BSWAP64(b);
|
||||
}
|
||||
|
||||
return b;
|
||||
return feof(f);
|
||||
}
|
||||
|
||||
uint64_t FileAccessUnix::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
|
||||
ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
|
||||
ERR_FAIL_NULL_V_MSG(f, -1, "File must be opened before use.");
|
||||
ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
|
||||
|
||||
uint64_t read = fread(p_dst, 1, p_length, f);
|
||||
check_errors();
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
|
|
@ -308,60 +302,25 @@ void FileAccessUnix::flush() {
|
|||
fflush(f);
|
||||
}
|
||||
|
||||
void FileAccessUnix::store_8(uint8_t p_dest) {
|
||||
ERR_FAIL_NULL_MSG(f, "File must be opened before use.");
|
||||
ERR_FAIL_COND(fwrite(&p_dest, 1, 1, f) != 1);
|
||||
}
|
||||
|
||||
void FileAccessUnix::store_16(uint16_t p_dest) {
|
||||
ERR_FAIL_NULL_MSG(f, "File must be opened before use.");
|
||||
|
||||
if (big_endian) {
|
||||
p_dest = BSWAP16(p_dest);
|
||||
}
|
||||
|
||||
ERR_FAIL_COND(fwrite(&p_dest, 1, 2, f) != 2);
|
||||
}
|
||||
|
||||
void FileAccessUnix::store_32(uint32_t p_dest) {
|
||||
ERR_FAIL_NULL_MSG(f, "File must be opened before use.");
|
||||
|
||||
if (big_endian) {
|
||||
p_dest = BSWAP32(p_dest);
|
||||
}
|
||||
|
||||
ERR_FAIL_COND(fwrite(&p_dest, 1, 4, f) != 4);
|
||||
}
|
||||
|
||||
void FileAccessUnix::store_64(uint64_t p_dest) {
|
||||
ERR_FAIL_NULL_MSG(f, "File must be opened before use.");
|
||||
|
||||
if (big_endian) {
|
||||
p_dest = BSWAP64(p_dest);
|
||||
}
|
||||
|
||||
ERR_FAIL_COND(fwrite(&p_dest, 1, 8, f) != 8);
|
||||
}
|
||||
|
||||
void FileAccessUnix::store_buffer(const uint8_t *p_src, uint64_t p_length) {
|
||||
ERR_FAIL_NULL_MSG(f, "File must be opened before use.");
|
||||
ERR_FAIL_COND(!p_src && p_length > 0);
|
||||
ERR_FAIL_COND(fwrite(p_src, 1, p_length, f) != p_length);
|
||||
bool FileAccessUnix::store_buffer(const uint8_t *p_src, uint64_t p_length) {
|
||||
ERR_FAIL_NULL_V_MSG(f, false, "File must be opened before use.");
|
||||
ERR_FAIL_COND_V(!p_src && p_length > 0, false);
|
||||
bool res = fwrite(p_src, 1, p_length, f) == p_length;
|
||||
check_errors(true);
|
||||
return res;
|
||||
}
|
||||
|
||||
bool FileAccessUnix::file_exists(const String &p_path) {
|
||||
int err;
|
||||
struct stat st = {};
|
||||
String filename = fix_path(p_path);
|
||||
const CharString filename_utf8 = fix_path(p_path).utf8();
|
||||
|
||||
// Does the name exist at all?
|
||||
err = stat(filename.utf8().get_data(), &st);
|
||||
if (err) {
|
||||
if (stat(filename_utf8.get_data(), &st)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// See if we have access to the file
|
||||
if (access(filename.utf8().get_data(), F_OK)) {
|
||||
if (access(filename_utf8.get_data(), F_OK)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -381,9 +340,18 @@ uint64_t FileAccessUnix::_get_modified_time(const String &p_file) {
|
|||
int err = stat(file.utf8().get_data(), &status);
|
||||
|
||||
if (!err) {
|
||||
return status.st_mtime;
|
||||
uint64_t modified_time = status.st_mtime;
|
||||
#ifdef ANDROID_ENABLED
|
||||
// Workaround for GH-101007
|
||||
//FIXME: After saving, all timestamps (st_mtime, st_ctime, st_atime) are set to the same value.
|
||||
// After exporting or after some time, only 'modified_time' resets to a past timestamp.
|
||||
uint64_t created_time = status.st_ctime;
|
||||
if (modified_time < created_time) {
|
||||
modified_time = created_time;
|
||||
}
|
||||
#endif
|
||||
return modified_time;
|
||||
} else {
|
||||
print_verbose("Failed to get modified time for: " + p_file + "");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -483,7 +451,7 @@ void FileAccessUnix::close() {
|
|||
_close();
|
||||
}
|
||||
|
||||
CloseNotificationFunc FileAccessUnix::close_notification_func = nullptr;
|
||||
FileAccessUnix::CloseNotificationFunc FileAccessUnix::close_notification_func = nullptr;
|
||||
|
||||
FileAccessUnix::~FileAccessUnix() {
|
||||
_close();
|
||||
|
|
|
|||
|
|
@ -38,12 +38,10 @@
|
|||
|
||||
#if defined(UNIX_ENABLED)
|
||||
|
||||
typedef void (*CloseNotificationFunc)(const String &p_file, int p_flags);
|
||||
|
||||
class FileAccessUnix : public FileAccess {
|
||||
FILE *f = nullptr;
|
||||
int flags = 0;
|
||||
void check_errors() const;
|
||||
void check_errors(bool p_write = false) const;
|
||||
mutable Error last_error = OK;
|
||||
String save_path;
|
||||
String path;
|
||||
|
|
@ -51,7 +49,12 @@ class FileAccessUnix : public FileAccess {
|
|||
|
||||
void _close();
|
||||
|
||||
#if defined(TOOLS_ENABLED)
|
||||
String get_real_path() const; // Returns the resolved real path for the current open file.
|
||||
#endif
|
||||
|
||||
public:
|
||||
typedef void (*CloseNotificationFunc)(const String &p_file, int p_flags);
|
||||
static CloseNotificationFunc close_notification_func;
|
||||
|
||||
virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
|
||||
|
|
@ -67,21 +70,13 @@ public:
|
|||
|
||||
virtual bool eof_reached() const override; ///< reading passed EOF
|
||||
|
||||
virtual uint8_t get_8() const override; ///< get a byte
|
||||
virtual uint16_t get_16() const override;
|
||||
virtual uint32_t get_32() const override;
|
||||
virtual uint64_t get_64() const override;
|
||||
virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
|
||||
|
||||
virtual Error get_error() const override; ///< get last error
|
||||
|
||||
virtual Error resize(int64_t p_length) override;
|
||||
virtual void flush() override;
|
||||
virtual void store_8(uint8_t p_dest) override; ///< store a byte
|
||||
virtual void store_16(uint16_t p_dest) override;
|
||||
virtual void store_32(uint32_t p_dest) override;
|
||||
virtual void store_64(uint64_t p_dest) override;
|
||||
virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes
|
||||
virtual bool store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes
|
||||
|
||||
virtual bool file_exists(const String &p_path) override; ///< return true if a file exists
|
||||
|
||||
|
|
|
|||
|
|
@ -37,11 +37,12 @@
|
|||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
Error FileAccessUnixPipe::open_existing(int p_rfd, int p_wfd) {
|
||||
Error FileAccessUnixPipe::open_existing(int p_rfd, int p_wfd, bool p_blocking) {
|
||||
// Open pipe using handles created by pipe(fd) call in the OS.execute_with_pipe.
|
||||
_close();
|
||||
|
||||
|
|
@ -51,6 +52,11 @@ Error FileAccessUnixPipe::open_existing(int p_rfd, int p_wfd) {
|
|||
fd[0] = p_rfd;
|
||||
fd[1] = p_wfd;
|
||||
|
||||
if (!p_blocking) {
|
||||
fcntl(fd[0], F_SETFL, fcntl(fd[0], F_GETFL) | O_NONBLOCK);
|
||||
fcntl(fd[1], F_SETFL, fcntl(fd[1], F_GETFL) | O_NONBLOCK);
|
||||
}
|
||||
|
||||
last_error = OK;
|
||||
return OK;
|
||||
}
|
||||
|
|
@ -62,10 +68,12 @@ Error FileAccessUnixPipe::open_internal(const String &p_path, int p_mode_flags)
|
|||
ERR_FAIL_COND_V_MSG(fd[0] >= 0 || fd[1] >= 0, ERR_ALREADY_IN_USE, "Pipe is already in use.");
|
||||
|
||||
path = String("/tmp/") + p_path.replace("pipe://", "").replace("/", "_");
|
||||
const CharString path_utf8 = path.utf8();
|
||||
|
||||
struct stat st = {};
|
||||
int err = stat(path.utf8().get_data(), &st);
|
||||
int err = stat(path_utf8.get_data(), &st);
|
||||
if (err) {
|
||||
if (mkfifo(path.utf8().get_data(), 0666) != 0) {
|
||||
if (mkfifo(path_utf8.get_data(), 0600) != 0) {
|
||||
last_error = ERR_FILE_CANT_OPEN;
|
||||
return last_error;
|
||||
}
|
||||
|
|
@ -74,7 +82,7 @@ Error FileAccessUnixPipe::open_internal(const String &p_path, int p_mode_flags)
|
|||
ERR_FAIL_COND_V_MSG(!S_ISFIFO(st.st_mode), ERR_ALREADY_IN_USE, "Pipe name is already used by file.");
|
||||
}
|
||||
|
||||
int f = ::open(path.utf8().get_data(), O_RDWR | O_CLOEXEC);
|
||||
int f = ::open(path_utf8.get_data(), O_RDWR | O_CLOEXEC | O_NONBLOCK);
|
||||
if (f < 0) {
|
||||
switch (errno) {
|
||||
case ENOENT: {
|
||||
|
|
@ -125,25 +133,23 @@ String FileAccessUnixPipe::get_path_absolute() const {
|
|||
return path_src;
|
||||
}
|
||||
|
||||
uint8_t FileAccessUnixPipe::get_8() const {
|
||||
uint64_t FileAccessUnixPipe::get_length() const {
|
||||
ERR_FAIL_COND_V_MSG(fd[0] < 0, 0, "Pipe must be opened before use.");
|
||||
|
||||
uint8_t b;
|
||||
if (::read(fd[0], &b, 1) == 0) {
|
||||
last_error = ERR_FILE_CANT_READ;
|
||||
b = '\0';
|
||||
} else {
|
||||
last_error = OK;
|
||||
}
|
||||
return b;
|
||||
int buf_rem = 0;
|
||||
ERR_FAIL_COND_V(ioctl(fd[0], FIONREAD, &buf_rem) != 0, 0);
|
||||
return buf_rem;
|
||||
}
|
||||
|
||||
uint64_t FileAccessUnixPipe::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
|
||||
ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
|
||||
ERR_FAIL_COND_V_MSG(fd[0] < 0, -1, "Pipe must be opened before use.");
|
||||
ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
|
||||
|
||||
uint64_t read = ::read(fd[0], p_dst, p_length);
|
||||
if (read == p_length) {
|
||||
ssize_t read = ::read(fd[0], p_dst, p_length);
|
||||
if (read == -1) {
|
||||
last_error = ERR_FILE_CANT_READ;
|
||||
read = 0;
|
||||
} else if (read != (ssize_t)p_length) {
|
||||
last_error = ERR_FILE_CANT_READ;
|
||||
} else {
|
||||
last_error = OK;
|
||||
|
|
@ -155,22 +161,16 @@ Error FileAccessUnixPipe::get_error() const {
|
|||
return last_error;
|
||||
}
|
||||
|
||||
void FileAccessUnixPipe::store_8(uint8_t p_src) {
|
||||
ERR_FAIL_COND_MSG(fd[1] < 0, "Pipe must be opened before use.");
|
||||
if (::write(fd[1], &p_src, 1) != 1) {
|
||||
last_error = ERR_FILE_CANT_WRITE;
|
||||
} else {
|
||||
last_error = OK;
|
||||
}
|
||||
}
|
||||
bool FileAccessUnixPipe::store_buffer(const uint8_t *p_src, uint64_t p_length) {
|
||||
ERR_FAIL_COND_V_MSG(fd[1] < 0, false, "Pipe must be opened before use.");
|
||||
ERR_FAIL_COND_V(!p_src && p_length > 0, false);
|
||||
|
||||
void FileAccessUnixPipe::store_buffer(const uint8_t *p_src, uint64_t p_length) {
|
||||
ERR_FAIL_COND_MSG(fd[1] < 0, "Pipe must be opened before use.");
|
||||
ERR_FAIL_COND(!p_src && p_length > 0);
|
||||
if (::write(fd[1], p_src, p_length) != (ssize_t)p_length) {
|
||||
last_error = ERR_FILE_CANT_WRITE;
|
||||
return false;
|
||||
} else {
|
||||
last_error = OK;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ class FileAccessUnixPipe : public FileAccess {
|
|||
void _close();
|
||||
|
||||
public:
|
||||
Error open_existing(int p_rfd, int p_wfd);
|
||||
Error open_existing(int p_rfd, int p_wfd, bool p_blocking);
|
||||
virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
|
||||
|
||||
virtual bool is_open() const override; ///< true when file is open
|
||||
|
|
@ -61,19 +61,17 @@ public:
|
|||
virtual void seek(uint64_t p_position) override {}
|
||||
virtual void seek_end(int64_t p_position = 0) override {}
|
||||
virtual uint64_t get_position() const override { return 0; }
|
||||
virtual uint64_t get_length() const override { return 0; }
|
||||
virtual uint64_t get_length() const override;
|
||||
|
||||
virtual bool eof_reached() const override { return false; }
|
||||
|
||||
virtual uint8_t get_8() const override; ///< get a byte
|
||||
virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
|
||||
|
||||
virtual Error get_error() const override; ///< get last error
|
||||
|
||||
virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; }
|
||||
virtual void flush() override {}
|
||||
virtual void store_8(uint8_t p_src) override; ///< store a byte
|
||||
virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes
|
||||
virtual bool store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes
|
||||
|
||||
virtual bool file_exists(const String &p_path) override { return false; }
|
||||
|
||||
|
|
|
|||
|
|
@ -28,23 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#if defined(UNIX_ENABLED) && !defined(UNIX_SOCKET_UNAVAILABLE)
|
||||
|
||||
#include "ip_unix.h"
|
||||
|
||||
#if defined(UNIX_ENABLED) || defined(WINDOWS_ENABLED)
|
||||
|
||||
#ifdef WINDOWS_ENABLED
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
#include <iphlpapi.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#else // UNIX
|
||||
|
||||
#include <netdb.h>
|
||||
|
||||
#ifdef ANDROID_ENABLED
|
||||
|
|
@ -67,8 +54,6 @@
|
|||
|
||||
#include <net/if.h> // Order is important on OpenBSD, leave as last.
|
||||
|
||||
#endif // UNIX
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static IPAddress _sockaddr2ip(struct sockaddr *p_addr) {
|
||||
|
|
@ -108,7 +93,7 @@ void IPUnix::_resolve_hostname(List<IPAddress> &r_addresses, const String &p_hos
|
|||
}
|
||||
|
||||
if (result == nullptr || result->ai_addr == nullptr) {
|
||||
print_verbose("Invalid response from getaddrinfo");
|
||||
print_verbose("Invalid response from getaddrinfo.");
|
||||
if (result) {
|
||||
freeaddrinfo(result);
|
||||
}
|
||||
|
|
@ -132,56 +117,6 @@ void IPUnix::_resolve_hostname(List<IPAddress> &r_addresses, const String &p_hos
|
|||
freeaddrinfo(result);
|
||||
}
|
||||
|
||||
#if defined(WINDOWS_ENABLED)
|
||||
|
||||
void IPUnix::get_local_interfaces(HashMap<String, Interface_Info> *r_interfaces) const {
|
||||
ULONG buf_size = 1024;
|
||||
IP_ADAPTER_ADDRESSES *addrs;
|
||||
|
||||
while (true) {
|
||||
addrs = (IP_ADAPTER_ADDRESSES *)memalloc(buf_size);
|
||||
int err = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME,
|
||||
nullptr, addrs, &buf_size);
|
||||
if (err == NO_ERROR) {
|
||||
break;
|
||||
}
|
||||
memfree(addrs);
|
||||
if (err == ERROR_BUFFER_OVERFLOW) {
|
||||
continue; // will go back and alloc the right size
|
||||
}
|
||||
|
||||
ERR_FAIL_MSG("Call to GetAdaptersAddresses failed with error " + itos(err) + ".");
|
||||
}
|
||||
|
||||
IP_ADAPTER_ADDRESSES *adapter = addrs;
|
||||
|
||||
while (adapter != nullptr) {
|
||||
Interface_Info info;
|
||||
info.name = adapter->AdapterName;
|
||||
info.name_friendly = adapter->FriendlyName;
|
||||
info.index = String::num_uint64(adapter->IfIndex);
|
||||
|
||||
IP_ADAPTER_UNICAST_ADDRESS *address = adapter->FirstUnicastAddress;
|
||||
while (address != nullptr) {
|
||||
int family = address->Address.lpSockaddr->sa_family;
|
||||
if (family != AF_INET && family != AF_INET6) {
|
||||
continue;
|
||||
}
|
||||
info.ip_addresses.push_front(_sockaddr2ip(address->Address.lpSockaddr));
|
||||
address = address->Next;
|
||||
}
|
||||
adapter = adapter->Next;
|
||||
// Only add interface if it has at least one IP
|
||||
if (info.ip_addresses.size() > 0) {
|
||||
r_interfaces->insert(info.name, info);
|
||||
}
|
||||
}
|
||||
|
||||
memfree(addrs);
|
||||
}
|
||||
|
||||
#else // UNIX
|
||||
|
||||
void IPUnix::get_local_interfaces(HashMap<String, Interface_Info> *r_interfaces) const {
|
||||
struct ifaddrs *ifAddrStruct = nullptr;
|
||||
struct ifaddrs *ifa = nullptr;
|
||||
|
|
@ -219,8 +154,6 @@ void IPUnix::get_local_interfaces(HashMap<String, Interface_Info> *r_interfaces)
|
|||
}
|
||||
}
|
||||
|
||||
#endif // UNIX
|
||||
|
||||
void IPUnix::make_default() {
|
||||
_create = _create_unix;
|
||||
}
|
||||
|
|
@ -232,4 +165,4 @@ IP *IPUnix::_create_unix() {
|
|||
IPUnix::IPUnix() {
|
||||
}
|
||||
|
||||
#endif // UNIX_ENABLED || WINDOWS_ENABLED
|
||||
#endif // UNIX_ENABLED
|
||||
|
|
|
|||
|
|
@ -31,9 +31,9 @@
|
|||
#ifndef IP_UNIX_H
|
||||
#define IP_UNIX_H
|
||||
|
||||
#include "core/io/ip.h"
|
||||
#if defined(UNIX_ENABLED) && !defined(UNIX_SOCKET_UNAVAILABLE)
|
||||
|
||||
#if defined(UNIX_ENABLED) || defined(WINDOWS_ENABLED)
|
||||
#include "core/io/ip.h"
|
||||
|
||||
class IPUnix : public IP {
|
||||
GDCLASS(IPUnix, IP);
|
||||
|
|
@ -49,6 +49,6 @@ public:
|
|||
IPUnix();
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // UNIX_ENABLED
|
||||
|
||||
#endif // IP_UNIX_H
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**************************************************************************/
|
||||
/* net_socket_posix.cpp */
|
||||
/* net_socket_unix.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
|
|
@ -28,13 +28,11 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "net_socket_posix.h"
|
||||
|
||||
// Some proprietary Unix-derived platforms don't expose Unix sockets
|
||||
// so this allows skipping this file to reimplement this API differently.
|
||||
#ifndef UNIX_SOCKET_UNAVAILABLE
|
||||
#if defined(UNIX_ENABLED) && !defined(UNIX_SOCKET_UNAVAILABLE)
|
||||
|
||||
#if defined(UNIX_ENABLED)
|
||||
#include "net_socket_unix.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
|
@ -62,42 +60,11 @@
|
|||
#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
|
||||
#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_CLOSE ::close
|
||||
#define SOCK_CONNECT(p_sock, p_addr, p_addr_len) ::connect(p_sock, p_addr, p_addr_len)
|
||||
|
||||
/* Windows */
|
||||
#elif defined(WINDOWS_ENABLED)
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
#include <mswsock.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_CLOSE closesocket
|
||||
// connect is broken on windows under certain conditions, reasons unknown:
|
||||
// See https://github.com/godotengine/webrtc-native/issues/6
|
||||
#define SOCK_CONNECT(p_sock, p_addr, p_addr_len) ::WSAConnect(p_sock, p_addr, p_addr_len, nullptr, nullptr, nullptr, nullptr)
|
||||
|
||||
// Workaround missing flag in MinGW
|
||||
#if defined(__MINGW32__) && !defined(SIO_UDP_NETRESET)
|
||||
#define SIO_UDP_NETRESET _WSAIOW(IOC_VENDOR, 15)
|
||||
#endif
|
||||
|
||||
#endif // UNIX_ENABLED
|
||||
|
||||
size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const IPAddress &p_ip, uint16_t p_port, IP::Type p_ip_type) {
|
||||
size_t NetSocketUnix::_set_addr_storage(struct sockaddr_storage *p_addr, const IPAddress &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
|
||||
if (p_ip_type == IP::TYPE_IPV6 || p_ip_type == IP::TYPE_ANY) { // IPv6 socket.
|
||||
|
||||
// IPv6 only socket with IPv4 address
|
||||
// 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;
|
||||
|
|
@ -109,14 +76,14 @@ size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const
|
|||
addr6->sin6_addr = in6addr_any;
|
||||
}
|
||||
return sizeof(sockaddr_in6);
|
||||
} else { // IPv4 socket
|
||||
} else { // IPv4 socket.
|
||||
|
||||
// IPv4 socket with IPv6 address
|
||||
// IPv4 socket with IPv6 address.
|
||||
ERR_FAIL_COND_V(!p_ip.is_wildcard() && !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
|
||||
addr4->sin_port = htons(p_port); // Short, network byte order.
|
||||
|
||||
if (p_ip.is_valid()) {
|
||||
memcpy(&addr4->sin_addr.s_addr, p_ip.get_ipv4(), 4);
|
||||
|
|
@ -128,7 +95,7 @@ size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const
|
|||
}
|
||||
}
|
||||
|
||||
void NetSocketPosix::_set_ip_port(struct sockaddr_storage *p_addr, IPAddress *r_ip, uint16_t *r_port) {
|
||||
void NetSocketUnix::_set_ip_port(struct sockaddr_storage *p_addr, IPAddress *r_ip, uint16_t *r_port) {
|
||||
if (p_addr->ss_family == AF_INET) {
|
||||
struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr;
|
||||
if (r_ip) {
|
||||
|
|
@ -148,34 +115,21 @@ void NetSocketPosix::_set_ip_port(struct sockaddr_storage *p_addr, IPAddress *r_
|
|||
}
|
||||
}
|
||||
|
||||
NetSocket *NetSocketPosix::_create_func() {
|
||||
return memnew(NetSocketPosix);
|
||||
NetSocket *NetSocketUnix::_create_func() {
|
||||
return memnew(NetSocketUnix);
|
||||
}
|
||||
|
||||
void NetSocketPosix::make_default() {
|
||||
#if defined(WINDOWS_ENABLED)
|
||||
if (_create == nullptr) {
|
||||
WSADATA data;
|
||||
WSAStartup(MAKEWORD(2, 2), &data);
|
||||
}
|
||||
#endif
|
||||
void NetSocketUnix::make_default() {
|
||||
_create = _create_func;
|
||||
}
|
||||
|
||||
void NetSocketPosix::cleanup() {
|
||||
#if defined(WINDOWS_ENABLED)
|
||||
if (_create != nullptr) {
|
||||
WSACleanup();
|
||||
}
|
||||
_create = nullptr;
|
||||
#endif
|
||||
void NetSocketUnix::cleanup() {
|
||||
}
|
||||
|
||||
NetSocketPosix::NetSocketPosix() :
|
||||
_sock(SOCK_EMPTY) {
|
||||
NetSocketUnix::NetSocketUnix() {
|
||||
}
|
||||
|
||||
NetSocketPosix::~NetSocketPosix() {
|
||||
NetSocketUnix::~NetSocketUnix() {
|
||||
close();
|
||||
}
|
||||
|
||||
|
|
@ -186,30 +140,7 @@ NetSocketPosix::~NetSocketPosix() {
|
|||
#pragma GCC diagnostic ignored "-Wlogical-op"
|
||||
#endif
|
||||
|
||||
NetSocketPosix::NetError NetSocketPosix::_get_socket_error() const {
|
||||
#if defined(WINDOWS_ENABLED)
|
||||
int err = WSAGetLastError();
|
||||
if (err == WSAEISCONN) {
|
||||
return ERR_NET_IS_CONNECTED;
|
||||
}
|
||||
if (err == WSAEINPROGRESS || err == WSAEALREADY) {
|
||||
return ERR_NET_IN_PROGRESS;
|
||||
}
|
||||
if (err == WSAEWOULDBLOCK) {
|
||||
return ERR_NET_WOULD_BLOCK;
|
||||
}
|
||||
if (err == WSAEADDRINUSE || err == WSAEADDRNOTAVAIL) {
|
||||
return ERR_NET_ADDRESS_INVALID_OR_UNAVAILABLE;
|
||||
}
|
||||
if (err == WSAEACCES) {
|
||||
return ERR_NET_UNAUTHORIZED;
|
||||
}
|
||||
if (err == WSAEMSGSIZE || err == WSAENOBUFS) {
|
||||
return ERR_NET_BUFFER_TOO_SMALL;
|
||||
}
|
||||
print_verbose("Socket error: " + itos(err));
|
||||
return ERR_NET_OTHER;
|
||||
#else
|
||||
NetSocketUnix::NetError NetSocketUnix::_get_socket_error() const {
|
||||
if (errno == EISCONN) {
|
||||
return ERR_NET_IS_CONNECTED;
|
||||
}
|
||||
|
|
@ -228,16 +159,15 @@ NetSocketPosix::NetError NetSocketPosix::_get_socket_error() const {
|
|||
if (errno == ENOBUFS) {
|
||||
return ERR_NET_BUFFER_TOO_SMALL;
|
||||
}
|
||||
print_verbose("Socket error: " + itos(errno));
|
||||
print_verbose("Socket error: " + itos(errno) + ".");
|
||||
return ERR_NET_OTHER;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
bool NetSocketPosix::_can_use_ip(const IPAddress &p_ip, const bool p_for_bind) const {
|
||||
bool NetSocketUnix::_can_use_ip(const IPAddress &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()) {
|
||||
|
|
@ -248,11 +178,11 @@ bool NetSocketPosix::_can_use_ip(const IPAddress &p_ip, const bool p_for_bind) c
|
|||
return !(_ip_type != IP::TYPE_ANY && !p_ip.is_wildcard() && _ip_type != type);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IPAddress p_ip, String p_if_name, bool p_add) {
|
||||
_FORCE_INLINE_ Error NetSocketUnix::_change_multicast_group(IPAddress p_ip, String p_if_name, bool p_add) {
|
||||
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
|
||||
ERR_FAIL_COND_V(!_can_use_ip(p_ip, false), ERR_INVALID_PARAMETER);
|
||||
|
||||
// Need to force level and af_family to IP(v4) when using dual stacking and provided multicast group is IPv4
|
||||
// Need to force level and af_family to IP(v4) when using dual stacking and provided multicast group is IPv4.
|
||||
IP::Type type = _ip_type == IP::TYPE_ANY && p_ip.is_ipv4() ? IP::TYPE_IPV4 : _ip_type;
|
||||
// This needs to be the proper level for the multicast group, no matter if the socket is dual stacking.
|
||||
int level = type == IP::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6;
|
||||
|
|
@ -275,7 +205,7 @@ _FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IPAddress p_ip, Str
|
|||
|
||||
for (const IPAddress &F : c.ip_addresses) {
|
||||
if (!F.is_ipv4()) {
|
||||
continue; // Wrong IP type
|
||||
continue; // Wrong IP type.
|
||||
}
|
||||
if_ip = F;
|
||||
break;
|
||||
|
|
@ -302,7 +232,7 @@ _FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IPAddress p_ip, Str
|
|||
return OK;
|
||||
}
|
||||
|
||||
void NetSocketPosix::_set_socket(SOCKET_TYPE p_sock, IP::Type p_ip_type, bool p_is_stream) {
|
||||
void NetSocketUnix::_set_socket(int p_sock, IP::Type p_ip_type, bool p_is_stream) {
|
||||
_sock = p_sock;
|
||||
_ip_type = p_ip_type;
|
||||
_is_stream = p_is_stream;
|
||||
|
|
@ -310,15 +240,13 @@ void NetSocketPosix::_set_socket(SOCKET_TYPE p_sock, IP::Type p_ip_type, bool p_
|
|||
_set_close_exec_enabled(true);
|
||||
}
|
||||
|
||||
void NetSocketPosix::_set_close_exec_enabled(bool p_enabled) {
|
||||
#ifndef WINDOWS_ENABLED
|
||||
void NetSocketUnix::_set_close_exec_enabled(bool p_enabled) {
|
||||
// Enable close on exec to avoid sharing with subprocesses. Off by default on Windows.
|
||||
int opts = fcntl(_sock, F_GETFD);
|
||||
fcntl(_sock, F_SETFD, opts | FD_CLOEXEC);
|
||||
#endif
|
||||
}
|
||||
|
||||
Error NetSocketPosix::open(Type p_sock_type, IP::Type &ip_type) {
|
||||
Error NetSocketUnix::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);
|
||||
|
||||
|
|
@ -334,7 +262,7 @@ Error NetSocketPosix::open(Type p_sock_type, IP::Type &ip_type) {
|
|||
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) {
|
||||
if (_sock == -1 && 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;
|
||||
|
|
@ -342,11 +270,11 @@ Error NetSocketPosix::open(Type p_sock_type, IP::Type &ip_type) {
|
|||
_sock = socket(family, type, protocol);
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V(_sock == SOCK_EMPTY, FAILED);
|
||||
ERR_FAIL_COND_V(_sock == -1, FAILED);
|
||||
_ip_type = ip_type;
|
||||
|
||||
if (family == AF_INET6) {
|
||||
// Select IPv4 over IPv6 mapping
|
||||
// Select IPv4 over IPv6 mapping.
|
||||
set_ipv6_only_enabled(ip_type != IP::TYPE_ANY);
|
||||
}
|
||||
|
||||
|
|
@ -361,41 +289,27 @@ Error NetSocketPosix::open(Type p_sock_type, IP::Type &ip_type) {
|
|||
// Disable descriptor sharing with subprocesses.
|
||||
_set_close_exec_enabled(true);
|
||||
|
||||
#if defined(WINDOWS_ENABLED)
|
||||
if (!_is_stream) {
|
||||
// Disable windows feature/bug reporting WSAECONNRESET/WSAENETRESET when
|
||||
// recv/recvfrom and an ICMP reply was received from a previous send/sendto.
|
||||
unsigned long disable = 0;
|
||||
if (ioctlsocket(_sock, SIO_UDP_CONNRESET, &disable) == SOCKET_ERROR) {
|
||||
print_verbose("Unable to turn off UDP WSAECONNRESET behavior on Windows");
|
||||
}
|
||||
if (ioctlsocket(_sock, SIO_UDP_NETRESET, &disable) == SOCKET_ERROR) {
|
||||
// This feature seems not to be supported on wine.
|
||||
print_verbose("Unable to turn off UDP WSAENETRESET behavior on Windows");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if defined(SO_NOSIGPIPE)
|
||||
// Disable SIGPIPE (should only be relevant to stream sockets, but seems to affect UDP too on iOS)
|
||||
// Disable SIGPIPE (should only be relevant to stream sockets, but seems to affect UDP too on iOS).
|
||||
int par = 1;
|
||||
if (setsockopt(_sock, SOL_SOCKET, SO_NOSIGPIPE, SOCK_CBUF(&par), sizeof(int)) != 0) {
|
||||
print_verbose("Unable to turn off SIGPIPE on socket");
|
||||
if (setsockopt(_sock, SOL_SOCKET, SO_NOSIGPIPE, &par, sizeof(int)) != 0) {
|
||||
print_verbose("Unable to turn off SIGPIPE on socket.");
|
||||
}
|
||||
#endif
|
||||
return OK;
|
||||
}
|
||||
|
||||
void NetSocketPosix::close() {
|
||||
if (_sock != SOCK_EMPTY) {
|
||||
SOCK_CLOSE(_sock);
|
||||
void NetSocketUnix::close() {
|
||||
if (_sock != -1) {
|
||||
::close(_sock);
|
||||
}
|
||||
|
||||
_sock = SOCK_EMPTY;
|
||||
_sock = -1;
|
||||
_ip_type = IP::TYPE_NONE;
|
||||
_is_stream = false;
|
||||
}
|
||||
|
||||
Error NetSocketPosix::bind(IPAddress p_addr, uint16_t p_port) {
|
||||
Error NetSocketUnix::bind(IPAddress 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);
|
||||
|
||||
|
|
@ -404,7 +318,7 @@ Error NetSocketPosix::bind(IPAddress p_addr, uint16_t p_port) {
|
|||
|
||||
if (::bind(_sock, (struct sockaddr *)&addr, addr_size) != 0) {
|
||||
NetError err = _get_socket_error();
|
||||
print_verbose("Failed to bind socket. Error: " + itos(err));
|
||||
print_verbose("Failed to bind socket. Error: " + itos(err) + ".");
|
||||
close();
|
||||
return ERR_UNAVAILABLE;
|
||||
}
|
||||
|
|
@ -412,7 +326,7 @@ Error NetSocketPosix::bind(IPAddress p_addr, uint16_t p_port) {
|
|||
return OK;
|
||||
}
|
||||
|
||||
Error NetSocketPosix::listen(int p_max_pending) {
|
||||
Error NetSocketUnix::listen(int p_max_pending) {
|
||||
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
|
||||
|
||||
if (::listen(_sock, p_max_pending) != 0) {
|
||||
|
|
@ -425,26 +339,26 @@ Error NetSocketPosix::listen(int p_max_pending) {
|
|||
return OK;
|
||||
}
|
||||
|
||||
Error NetSocketPosix::connect_to_host(IPAddress p_host, uint16_t p_port) {
|
||||
Error NetSocketUnix::connect_to_host(IPAddress 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 (SOCK_CONNECT(_sock, (struct sockaddr *)&addr, addr_size) != 0) {
|
||||
if (::connect(_sock, (struct sockaddr *)&addr, addr_size) != 0) {
|
||||
NetError err = _get_socket_error();
|
||||
|
||||
switch (err) {
|
||||
// We are already connected
|
||||
// We are already connected.
|
||||
case ERR_NET_IS_CONNECTED:
|
||||
return OK;
|
||||
// Still waiting to connect, try again in a while
|
||||
// Still waiting to connect, try again in a while.
|
||||
case ERR_NET_WOULD_BLOCK:
|
||||
case ERR_NET_IN_PROGRESS:
|
||||
return ERR_BUSY;
|
||||
default:
|
||||
print_verbose("Connection to remote host failed!");
|
||||
print_verbose("Connection to remote host failed.");
|
||||
close();
|
||||
return FAILED;
|
||||
}
|
||||
|
|
@ -453,66 +367,9 @@ Error NetSocketPosix::connect_to_host(IPAddress p_host, uint16_t p_port) {
|
|||
return OK;
|
||||
}
|
||||
|
||||
Error NetSocketPosix::poll(PollType p_type, int p_timeout) const {
|
||||
Error NetSocketUnix::poll(PollType p_type, int p_timeout) const {
|
||||
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
|
||||
|
||||
#if defined(WINDOWS_ENABLED)
|
||||
bool ready = false;
|
||||
fd_set rd, wr, ex;
|
||||
fd_set *rdp = nullptr;
|
||||
fd_set *wrp = nullptr;
|
||||
FD_ZERO(&rd);
|
||||
FD_ZERO(&wr);
|
||||
FD_ZERO(&ex);
|
||||
FD_SET(_sock, &ex);
|
||||
struct timeval timeout = { p_timeout / 1000, (p_timeout % 1000) * 1000 };
|
||||
// For blocking operation, pass nullptr timeout pointer to select.
|
||||
struct timeval *tp = nullptr;
|
||||
if (p_timeout >= 0) {
|
||||
// If timeout is non-negative, we want to specify the timeout instead.
|
||||
tp = &timeout;
|
||||
}
|
||||
|
||||
switch (p_type) {
|
||||
case POLL_TYPE_IN:
|
||||
FD_SET(_sock, &rd);
|
||||
rdp = &rd;
|
||||
break;
|
||||
case POLL_TYPE_OUT:
|
||||
FD_SET(_sock, &wr);
|
||||
wrp = ≀
|
||||
break;
|
||||
case POLL_TYPE_IN_OUT:
|
||||
FD_SET(_sock, &rd);
|
||||
FD_SET(_sock, &wr);
|
||||
rdp = &rd;
|
||||
wrp = ≀
|
||||
}
|
||||
int ret = select(1, rdp, wrp, &ex, tp);
|
||||
|
||||
if (ret == SOCKET_ERROR) {
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
return ERR_BUSY;
|
||||
}
|
||||
|
||||
if (FD_ISSET(_sock, &ex)) {
|
||||
_get_socket_error();
|
||||
print_verbose("Exception when polling socket.");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
if (rdp && FD_ISSET(_sock, rdp)) {
|
||||
ready = true;
|
||||
}
|
||||
if (wrp && FD_ISSET(_sock, wrp)) {
|
||||
ready = true;
|
||||
}
|
||||
|
||||
return ready ? OK : ERR_BUSY;
|
||||
#else
|
||||
struct pollfd pfd;
|
||||
pfd.fd = _sock;
|
||||
pfd.events = POLLIN;
|
||||
|
|
@ -542,13 +399,12 @@ Error NetSocketPosix::poll(PollType p_type, int p_timeout) const {
|
|||
}
|
||||
|
||||
return OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
Error NetSocketPosix::recv(uint8_t *p_buffer, int p_len, int &r_read) {
|
||||
Error NetSocketUnix::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);
|
||||
r_read = ::recv(_sock, p_buffer, p_len, 0);
|
||||
|
||||
if (r_read < 0) {
|
||||
NetError err = _get_socket_error();
|
||||
|
|
@ -566,14 +422,14 @@ Error NetSocketPosix::recv(uint8_t *p_buffer, int p_len, int &r_read) {
|
|||
return OK;
|
||||
}
|
||||
|
||||
Error NetSocketPosix::recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IPAddress &r_ip, uint16_t &r_port, bool p_peek) {
|
||||
Error NetSocketUnix::recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IPAddress &r_ip, uint16_t &r_port, bool p_peek) {
|
||||
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, p_peek ? MSG_PEEK : 0, (struct sockaddr *)&from, &len);
|
||||
r_read = ::recvfrom(_sock, p_buffer, p_len, p_peek ? MSG_PEEK : 0, (struct sockaddr *)&from, &len);
|
||||
|
||||
if (r_read < 0) {
|
||||
NetError err = _get_socket_error();
|
||||
|
|
@ -604,7 +460,7 @@ Error NetSocketPosix::recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IPAddr
|
|||
return OK;
|
||||
}
|
||||
|
||||
Error NetSocketPosix::send(const uint8_t *p_buffer, int p_len, int &r_sent) {
|
||||
Error NetSocketUnix::send(const uint8_t *p_buffer, int p_len, int &r_sent) {
|
||||
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
|
||||
|
||||
int flags = 0;
|
||||
|
|
@ -613,7 +469,7 @@ Error NetSocketPosix::send(const uint8_t *p_buffer, int p_len, int &r_sent) {
|
|||
flags = MSG_NOSIGNAL;
|
||||
}
|
||||
#endif
|
||||
r_sent = ::send(_sock, SOCK_CBUF(p_buffer), p_len, flags);
|
||||
r_sent = ::send(_sock, p_buffer, p_len, flags);
|
||||
|
||||
if (r_sent < 0) {
|
||||
NetError err = _get_socket_error();
|
||||
|
|
@ -630,12 +486,12 @@ Error NetSocketPosix::send(const uint8_t *p_buffer, int p_len, int &r_sent) {
|
|||
return OK;
|
||||
}
|
||||
|
||||
Error NetSocketPosix::sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IPAddress p_ip, uint16_t p_port) {
|
||||
Error NetSocketUnix::sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IPAddress 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);
|
||||
r_sent = ::sendto(_sock, p_buffer, p_len, 0, (struct sockaddr *)&addr, addr_size);
|
||||
|
||||
if (r_sent < 0) {
|
||||
NetError err = _get_socket_error();
|
||||
|
|
@ -652,7 +508,7 @@ Error NetSocketPosix::sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP
|
|||
return OK;
|
||||
}
|
||||
|
||||
Error NetSocketPosix::set_broadcasting_enabled(bool p_enabled) {
|
||||
Error NetSocketUnix::set_broadcasting_enabled(bool p_enabled) {
|
||||
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
|
||||
// IPv6 has no broadcast support.
|
||||
if (_ip_type == IP::TYPE_IPV6) {
|
||||
|
|
@ -660,90 +516,68 @@ Error NetSocketPosix::set_broadcasting_enabled(bool p_enabled) {
|
|||
}
|
||||
|
||||
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");
|
||||
if (setsockopt(_sock, SOL_SOCKET, SO_BROADCAST, &par, sizeof(int)) != 0) {
|
||||
WARN_PRINT("Unable to change broadcast setting.");
|
||||
return FAILED;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
void NetSocketPosix::set_blocking_enabled(bool p_enabled) {
|
||||
void NetSocketUnix::set_blocking_enabled(bool p_enabled) {
|
||||
ERR_FAIL_COND(!is_open());
|
||||
|
||||
int ret = 0;
|
||||
#if defined(WINDOWS_ENABLED)
|
||||
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");
|
||||
WARN_PRINT("Unable to change non-block mode.");
|
||||
}
|
||||
}
|
||||
|
||||
void NetSocketPosix::set_ipv6_only_enabled(bool p_enabled) {
|
||||
void NetSocketUnix::set_ipv6_only_enabled(bool p_enabled) {
|
||||
ERR_FAIL_COND(!is_open());
|
||||
// This option is only available 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");
|
||||
if (setsockopt(_sock, IPPROTO_IPV6, IPV6_V6ONLY, &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) {
|
||||
void NetSocketUnix::set_tcp_no_delay_enabled(bool p_enabled) {
|
||||
ERR_FAIL_COND(!is_open());
|
||||
ERR_FAIL_COND(!_is_stream); // Not TCP
|
||||
ERR_FAIL_COND(!_is_stream); // Not 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");
|
||||
if (setsockopt(_sock, IPPROTO_TCP, TCP_NODELAY, &par, sizeof(int)) < 0) {
|
||||
WARN_PRINT("Unable to set TCP no delay option.");
|
||||
}
|
||||
}
|
||||
|
||||
void NetSocketPosix::set_reuse_address_enabled(bool p_enabled) {
|
||||
void NetSocketUnix::set_reuse_address_enabled(bool p_enabled) {
|
||||
ERR_FAIL_COND(!is_open());
|
||||
|
||||
// On Windows, enabling SO_REUSEADDR actually would also enable reuse port, very bad on TCP. Denying...
|
||||
// Windows does not have this option, SO_REUSEADDR in this magical world means SO_REUSEPORT
|
||||
#ifndef WINDOWS_ENABLED
|
||||
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!");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void NetSocketPosix::set_reuse_port_enabled(bool p_enabled) {
|
||||
ERR_FAIL_COND(!is_open());
|
||||
|
||||
// See comment above...
|
||||
#ifdef WINDOWS_ENABLED
|
||||
#define SO_REUSEPORT SO_REUSEADDR
|
||||
#endif
|
||||
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!");
|
||||
if (setsockopt(_sock, SOL_SOCKET, SO_REUSEADDR, &par, sizeof(int)) < 0) {
|
||||
WARN_PRINT("Unable to set socket REUSEADDR option.");
|
||||
}
|
||||
}
|
||||
|
||||
bool NetSocketPosix::is_open() const {
|
||||
return _sock != SOCK_EMPTY;
|
||||
bool NetSocketUnix::is_open() const {
|
||||
return _sock != -1;
|
||||
}
|
||||
|
||||
int NetSocketPosix::get_available_bytes() const {
|
||||
int NetSocketUnix::get_available_bytes() const {
|
||||
ERR_FAIL_COND_V(!is_open(), -1);
|
||||
|
||||
unsigned long len;
|
||||
int ret = SOCK_IOCTL(_sock, FIONREAD, &len);
|
||||
int len;
|
||||
int ret = ioctl(_sock, FIONREAD, &len);
|
||||
if (ret == -1) {
|
||||
_get_socket_error();
|
||||
print_verbose("Error when checking available bytes on socket.");
|
||||
|
|
@ -752,7 +586,7 @@ int NetSocketPosix::get_available_bytes() const {
|
|||
return len;
|
||||
}
|
||||
|
||||
Error NetSocketPosix::get_socket_address(IPAddress *r_ip, uint16_t *r_port) const {
|
||||
Error NetSocketUnix::get_socket_address(IPAddress *r_ip, uint16_t *r_port) const {
|
||||
ERR_FAIL_COND_V(!is_open(), FAILED);
|
||||
|
||||
struct sockaddr_storage saddr;
|
||||
|
|
@ -766,14 +600,14 @@ Error NetSocketPosix::get_socket_address(IPAddress *r_ip, uint16_t *r_port) cons
|
|||
return OK;
|
||||
}
|
||||
|
||||
Ref<NetSocket> NetSocketPosix::accept(IPAddress &r_ip, uint16_t &r_port) {
|
||||
Ref<NetSocket> NetSocketUnix::accept(IPAddress &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);
|
||||
if (fd == SOCK_EMPTY) {
|
||||
int fd = ::accept(_sock, (struct sockaddr *)&their_addr, &size);
|
||||
if (fd == -1) {
|
||||
_get_socket_error();
|
||||
print_verbose("Error when accepting socket connection.");
|
||||
return out;
|
||||
|
|
@ -781,18 +615,18 @@ Ref<NetSocket> NetSocketPosix::accept(IPAddress &r_ip, uint16_t &r_port) {
|
|||
|
||||
_set_ip_port(&their_addr, &r_ip, &r_port);
|
||||
|
||||
NetSocketPosix *ns = memnew(NetSocketPosix);
|
||||
NetSocketUnix *ns = memnew(NetSocketUnix);
|
||||
ns->_set_socket(fd, _ip_type, _is_stream);
|
||||
ns->set_blocking_enabled(false);
|
||||
return Ref<NetSocket>(ns);
|
||||
}
|
||||
|
||||
Error NetSocketPosix::join_multicast_group(const IPAddress &p_multi_address, const String &p_if_name) {
|
||||
Error NetSocketUnix::join_multicast_group(const IPAddress &p_multi_address, const String &p_if_name) {
|
||||
return _change_multicast_group(p_multi_address, p_if_name, true);
|
||||
}
|
||||
|
||||
Error NetSocketPosix::leave_multicast_group(const IPAddress &p_multi_address, const String &p_if_name) {
|
||||
Error NetSocketUnix::leave_multicast_group(const IPAddress &p_multi_address, const String &p_if_name) {
|
||||
return _change_multicast_group(p_multi_address, p_if_name, false);
|
||||
}
|
||||
|
||||
#endif // UNIX_SOCKET_UNAVAILABLE
|
||||
#endif // UNIX_ENABLED && !UNIX_SOCKET_UNAVAILABLE
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/**************************************************************************/
|
||||
/* net_socket_posix.h */
|
||||
/* net_socket_unix.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
|
|
@ -28,25 +28,18 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef NET_SOCKET_POSIX_H
|
||||
#define NET_SOCKET_POSIX_H
|
||||
#ifndef NET_SOCKET_UNIX_H
|
||||
#define NET_SOCKET_UNIX_H
|
||||
|
||||
#if defined(UNIX_ENABLED) && !defined(UNIX_SOCKET_UNAVAILABLE)
|
||||
|
||||
#include "core/io/net_socket.h"
|
||||
|
||||
#if defined(WINDOWS_ENABLED)
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#define SOCKET_TYPE SOCKET
|
||||
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#define SOCKET_TYPE int
|
||||
|
||||
#endif
|
||||
|
||||
class NetSocketPosix : public NetSocket {
|
||||
class NetSocketUnix : public NetSocket {
|
||||
private:
|
||||
SOCKET_TYPE _sock; // NOLINT - the default value is defined in the .cpp
|
||||
int _sock = -1;
|
||||
IP::Type _ip_type = IP::TYPE_NONE;
|
||||
bool _is_stream = false;
|
||||
|
||||
|
|
@ -61,7 +54,7 @@ private:
|
|||
};
|
||||
|
||||
NetError _get_socket_error() const;
|
||||
void _set_socket(SOCKET_TYPE p_sock, IP::Type p_ip_type, bool p_is_stream);
|
||||
void _set_socket(int p_sock, IP::Type p_ip_type, bool p_is_stream);
|
||||
_FORCE_INLINE_ Error _change_multicast_group(IPAddress p_ip, String p_if_name, bool p_add);
|
||||
_FORCE_INLINE_ void _set_close_exec_enabled(bool p_enabled);
|
||||
|
||||
|
|
@ -76,33 +69,34 @@ public:
|
|||
static void _set_ip_port(struct sockaddr_storage *p_addr, IPAddress *r_ip, uint16_t *r_port);
|
||||
static size_t _set_addr_storage(struct sockaddr_storage *p_addr, const IPAddress &p_ip, uint16_t p_port, IP::Type p_ip_type);
|
||||
|
||||
virtual Error open(Type p_sock_type, IP::Type &ip_type);
|
||||
virtual void close();
|
||||
virtual Error bind(IPAddress p_addr, uint16_t p_port);
|
||||
virtual Error listen(int p_max_pending);
|
||||
virtual Error connect_to_host(IPAddress p_host, 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, IPAddress &r_ip, uint16_t &r_port, bool p_peek = false);
|
||||
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, IPAddress p_ip, uint16_t p_port);
|
||||
virtual Ref<NetSocket> accept(IPAddress &r_ip, uint16_t &r_port);
|
||||
virtual Error open(Type p_sock_type, IP::Type &ip_type) override;
|
||||
virtual void close() override;
|
||||
virtual Error bind(IPAddress p_addr, uint16_t p_port) override;
|
||||
virtual Error listen(int p_max_pending) override;
|
||||
virtual Error connect_to_host(IPAddress p_host, uint16_t p_port) override;
|
||||
virtual Error poll(PollType p_type, int timeout) const override;
|
||||
virtual Error recv(uint8_t *p_buffer, int p_len, int &r_read) override;
|
||||
virtual Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IPAddress &r_ip, uint16_t &r_port, bool p_peek = false) override;
|
||||
virtual Error send(const uint8_t *p_buffer, int p_len, int &r_sent) override;
|
||||
virtual Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IPAddress p_ip, uint16_t p_port) override;
|
||||
virtual Ref<NetSocket> accept(IPAddress &r_ip, uint16_t &r_port) override;
|
||||
|
||||
virtual bool is_open() const;
|
||||
virtual int get_available_bytes() const;
|
||||
virtual Error get_socket_address(IPAddress *r_ip, uint16_t *r_port) const;
|
||||
virtual bool is_open() const override;
|
||||
virtual int get_available_bytes() const override;
|
||||
virtual Error get_socket_address(IPAddress *r_ip, uint16_t *r_port) const override;
|
||||
|
||||
virtual Error 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 Error join_multicast_group(const IPAddress &p_multi_address, const String &p_if_name);
|
||||
virtual Error leave_multicast_group(const IPAddress &p_multi_address, const String &p_if_name);
|
||||
virtual Error set_broadcasting_enabled(bool p_enabled) override;
|
||||
virtual void set_blocking_enabled(bool p_enabled) override;
|
||||
virtual void set_ipv6_only_enabled(bool p_enabled) override;
|
||||
virtual void set_tcp_no_delay_enabled(bool p_enabled) override;
|
||||
virtual void set_reuse_address_enabled(bool p_enabled) override;
|
||||
virtual Error join_multicast_group(const IPAddress &p_multi_address, const String &p_if_name) override;
|
||||
virtual Error leave_multicast_group(const IPAddress &p_multi_address, const String &p_if_name) override;
|
||||
|
||||
NetSocketPosix();
|
||||
~NetSocketPosix();
|
||||
NetSocketUnix();
|
||||
~NetSocketUnix() override;
|
||||
};
|
||||
|
||||
#endif // NET_SOCKET_POSIX_H
|
||||
#endif // UNIX_ENABLED && !UNIX_SOCKET_UNAVAILABLE
|
||||
|
||||
#endif // NET_SOCKET_UNIX_H
|
||||
|
|
@ -38,7 +38,7 @@
|
|||
#include "drivers/unix/dir_access_unix.h"
|
||||
#include "drivers/unix/file_access_unix.h"
|
||||
#include "drivers/unix/file_access_unix_pipe.h"
|
||||
#include "drivers/unix/net_socket_posix.h"
|
||||
#include "drivers/unix/net_socket_unix.h"
|
||||
#include "drivers/unix/thread_posix.h"
|
||||
#include "servers/rendering_server.h"
|
||||
|
||||
|
|
@ -77,6 +77,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
#include <time.h>
|
||||
|
|
@ -166,8 +167,10 @@ void OS_Unix::initialize_core() {
|
|||
DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_USERDATA);
|
||||
DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_FILESYSTEM);
|
||||
|
||||
NetSocketPosix::make_default();
|
||||
#ifndef UNIX_SOCKET_UNAVAILABLE
|
||||
NetSocketUnix::make_default();
|
||||
IPUnix::make_default();
|
||||
#endif
|
||||
process_map = memnew((HashMap<ProcessID, ProcessInfo>));
|
||||
|
||||
_setup_clock();
|
||||
|
|
@ -175,16 +178,96 @@ void OS_Unix::initialize_core() {
|
|||
|
||||
void OS_Unix::finalize_core() {
|
||||
memdelete(process_map);
|
||||
NetSocketPosix::cleanup();
|
||||
#ifndef UNIX_SOCKET_UNAVAILABLE
|
||||
NetSocketUnix::cleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
Vector<String> OS_Unix::get_video_adapter_driver_info() const {
|
||||
return Vector<String>();
|
||||
}
|
||||
|
||||
String OS_Unix::get_stdin_string() {
|
||||
char buff[1024];
|
||||
return String::utf8(fgets(buff, 1024, stdin));
|
||||
String OS_Unix::get_stdin_string(int64_t p_buffer_size) {
|
||||
Vector<uint8_t> data;
|
||||
data.resize(p_buffer_size);
|
||||
if (fgets((char *)data.ptrw(), data.size(), stdin)) {
|
||||
return String::utf8((char *)data.ptr()).replace("\r\n", "\n").rstrip("\n");
|
||||
}
|
||||
return String();
|
||||
}
|
||||
|
||||
PackedByteArray OS_Unix::get_stdin_buffer(int64_t p_buffer_size) {
|
||||
Vector<uint8_t> data;
|
||||
data.resize(p_buffer_size);
|
||||
size_t sz = fread((void *)data.ptrw(), 1, data.size(), stdin);
|
||||
if (sz > 0) {
|
||||
data.resize(sz);
|
||||
return data;
|
||||
}
|
||||
return PackedByteArray();
|
||||
}
|
||||
|
||||
OS_Unix::StdHandleType OS_Unix::get_stdin_type() const {
|
||||
int h = fileno(stdin);
|
||||
if (h == -1) {
|
||||
return STD_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
if (isatty(h)) {
|
||||
return STD_HANDLE_CONSOLE;
|
||||
}
|
||||
struct stat statbuf;
|
||||
if (fstat(h, &statbuf) < 0) {
|
||||
return STD_HANDLE_UNKNOWN;
|
||||
}
|
||||
if (S_ISFIFO(statbuf.st_mode)) {
|
||||
return STD_HANDLE_PIPE;
|
||||
} else if (S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode)) {
|
||||
return STD_HANDLE_FILE;
|
||||
}
|
||||
return STD_HANDLE_UNKNOWN;
|
||||
}
|
||||
|
||||
OS_Unix::StdHandleType OS_Unix::get_stdout_type() const {
|
||||
int h = fileno(stdout);
|
||||
if (h == -1) {
|
||||
return STD_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
if (isatty(h)) {
|
||||
return STD_HANDLE_CONSOLE;
|
||||
}
|
||||
struct stat statbuf;
|
||||
if (fstat(h, &statbuf) < 0) {
|
||||
return STD_HANDLE_UNKNOWN;
|
||||
}
|
||||
if (S_ISFIFO(statbuf.st_mode)) {
|
||||
return STD_HANDLE_PIPE;
|
||||
} else if (S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode)) {
|
||||
return STD_HANDLE_FILE;
|
||||
}
|
||||
return STD_HANDLE_UNKNOWN;
|
||||
}
|
||||
|
||||
OS_Unix::StdHandleType OS_Unix::get_stderr_type() const {
|
||||
int h = fileno(stderr);
|
||||
if (h == -1) {
|
||||
return STD_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
if (isatty(h)) {
|
||||
return STD_HANDLE_CONSOLE;
|
||||
}
|
||||
struct stat statbuf;
|
||||
if (fstat(h, &statbuf) < 0) {
|
||||
return STD_HANDLE_UNKNOWN;
|
||||
}
|
||||
if (S_ISFIFO(statbuf.st_mode)) {
|
||||
return STD_HANDLE_PIPE;
|
||||
} else if (S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode)) {
|
||||
return STD_HANDLE_FILE;
|
||||
}
|
||||
return STD_HANDLE_UNKNOWN;
|
||||
}
|
||||
|
||||
Error OS_Unix::get_entropy(uint8_t *r_buffer, int p_bytes) {
|
||||
|
|
@ -225,6 +308,10 @@ String OS_Unix::get_version() const {
|
|||
return "";
|
||||
}
|
||||
|
||||
String OS_Unix::get_temp_path() const {
|
||||
return "/tmp";
|
||||
}
|
||||
|
||||
double OS_Unix::get_unix_time() const {
|
||||
struct timeval tv_now;
|
||||
gettimeofday(&tv_now, nullptr);
|
||||
|
|
@ -493,7 +580,7 @@ Dictionary OS_Unix::get_memory_info() const {
|
|||
return meminfo;
|
||||
}
|
||||
|
||||
Dictionary OS_Unix::execute_with_pipe(const String &p_path, const List<String> &p_arguments) {
|
||||
Dictionary OS_Unix::execute_with_pipe(const String &p_path, const List<String> &p_arguments, bool p_blocking) {
|
||||
#define CLEAN_PIPES \
|
||||
if (pipe_in[0] >= 0) { \
|
||||
::close(pipe_in[0]); \
|
||||
|
|
@ -578,11 +665,11 @@ Dictionary OS_Unix::execute_with_pipe(const String &p_path, const List<String> &
|
|||
|
||||
Ref<FileAccessUnixPipe> main_pipe;
|
||||
main_pipe.instantiate();
|
||||
main_pipe->open_existing(pipe_out[0], pipe_in[1]);
|
||||
main_pipe->open_existing(pipe_out[0], pipe_in[1], p_blocking);
|
||||
|
||||
Ref<FileAccessUnixPipe> err_pipe;
|
||||
err_pipe.instantiate();
|
||||
err_pipe->open_existing(pipe_err[0], 0);
|
||||
err_pipe->open_existing(pipe_err[0], 0, p_blocking);
|
||||
|
||||
ProcessInfo pi;
|
||||
process_map_mutex.lock();
|
||||
|
|
@ -777,7 +864,7 @@ String OS_Unix::get_locale() const {
|
|||
}
|
||||
|
||||
String locale = get_environment("LANG");
|
||||
int tp = locale.find(".");
|
||||
int tp = locale.find_char('.');
|
||||
if (tp != -1) {
|
||||
locale = locale.substr(0, tp);
|
||||
}
|
||||
|
|
@ -862,32 +949,18 @@ String OS_Unix::get_environment(const String &p_var) const {
|
|||
}
|
||||
|
||||
void OS_Unix::set_environment(const String &p_var, const String &p_value) const {
|
||||
ERR_FAIL_COND_MSG(p_var.is_empty() || p_var.contains("="), vformat("Invalid environment variable name '%s', cannot be empty or include '='.", p_var));
|
||||
ERR_FAIL_COND_MSG(p_var.is_empty() || p_var.contains_char('='), vformat("Invalid environment variable name '%s', cannot be empty or include '='.", p_var));
|
||||
int err = setenv(p_var.utf8().get_data(), p_value.utf8().get_data(), /* overwrite: */ 1);
|
||||
ERR_FAIL_COND_MSG(err != 0, vformat("Failed setting environment variable '%s', the system is out of memory.", p_var));
|
||||
}
|
||||
|
||||
void OS_Unix::unset_environment(const String &p_var) const {
|
||||
ERR_FAIL_COND_MSG(p_var.is_empty() || p_var.contains("="), vformat("Invalid environment variable name '%s', cannot be empty or include '='.", p_var));
|
||||
ERR_FAIL_COND_MSG(p_var.is_empty() || p_var.contains_char('='), vformat("Invalid environment variable name '%s', cannot be empty or include '='.", p_var));
|
||||
unsetenv(p_var.utf8().get_data());
|
||||
}
|
||||
|
||||
String OS_Unix::get_user_data_dir() const {
|
||||
String appname = get_safe_dir_name(GLOBAL_GET("application/config/name"));
|
||||
if (!appname.is_empty()) {
|
||||
bool use_custom_dir = GLOBAL_GET("application/config/use_custom_user_dir");
|
||||
if (use_custom_dir) {
|
||||
String custom_dir = get_safe_dir_name(GLOBAL_GET("application/config/custom_user_dir_name"), true);
|
||||
if (custom_dir.is_empty()) {
|
||||
custom_dir = appname;
|
||||
}
|
||||
return get_data_path().path_join(custom_dir);
|
||||
} else {
|
||||
return get_data_path().path_join(get_godot_dir_name()).path_join("app_userdata").path_join(appname);
|
||||
}
|
||||
}
|
||||
|
||||
return get_data_path().path_join(get_godot_dir_name()).path_join("app_userdata").path_join("[unnamed project]");
|
||||
String OS_Unix::get_user_data_dir(const String &p_user_dir) const {
|
||||
return get_data_path().path_join(p_user_dir);
|
||||
}
|
||||
|
||||
String OS_Unix::get_executable_path() const {
|
||||
|
|
|
|||
|
|
@ -58,7 +58,11 @@ public:
|
|||
|
||||
virtual Vector<String> get_video_adapter_driver_info() const override;
|
||||
|
||||
virtual String get_stdin_string() override;
|
||||
virtual String get_stdin_string(int64_t p_buffer_size = 1024) override;
|
||||
virtual PackedByteArray get_stdin_buffer(int64_t p_buffer_size = 1024) override;
|
||||
virtual StdHandleType get_stdin_type() const override;
|
||||
virtual StdHandleType get_stdout_type() const override;
|
||||
virtual StdHandleType get_stderr_type() const override;
|
||||
|
||||
virtual Error get_entropy(uint8_t *r_buffer, int p_bytes) override;
|
||||
|
||||
|
|
@ -72,6 +76,8 @@ public:
|
|||
virtual String get_distribution_name() const override;
|
||||
virtual String get_version() const override;
|
||||
|
||||
virtual String get_temp_path() const override;
|
||||
|
||||
virtual DateTime get_datetime(bool p_utc) const override;
|
||||
virtual TimeZoneInfo get_time_zone_info() const override;
|
||||
|
||||
|
|
@ -83,7 +89,7 @@ public:
|
|||
virtual Dictionary get_memory_info() const override;
|
||||
|
||||
virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr, bool p_open_console = false) override;
|
||||
virtual Dictionary execute_with_pipe(const String &p_path, const List<String> &p_arguments) override;
|
||||
virtual Dictionary execute_with_pipe(const String &p_path, const List<String> &p_arguments, bool p_blocking = true) override;
|
||||
virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) override;
|
||||
virtual Error kill(const ProcessID &p_pid) override;
|
||||
virtual int get_process_id() const override;
|
||||
|
|
@ -100,7 +106,7 @@ public:
|
|||
virtual void initialize_debugging() override;
|
||||
|
||||
virtual String get_executable_path() const override;
|
||||
virtual String get_user_data_dir() const override;
|
||||
virtual String get_user_data_dir(const String &p_user_dir) const override;
|
||||
};
|
||||
|
||||
class UnixTerminalLogger : public StdLogger {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue