diff options
Diffstat (limited to 'drivers/unix')
-rw-r--r-- | drivers/unix/dir_access_unix.cpp | 208 | ||||
-rw-r--r-- | drivers/unix/dir_access_unix.h | 64 | ||||
-rw-r--r-- | drivers/unix/file_access_unix.cpp | 100 | ||||
-rw-r--r-- | drivers/unix/file_access_unix.h | 54 | ||||
-rw-r--r-- | drivers/unix/ip_unix.cpp | 103 | ||||
-rw-r--r-- | drivers/unix/ip_unix.h | 15 | ||||
-rw-r--r-- | drivers/unix/net_socket_posix.cpp | 169 | ||||
-rw-r--r-- | drivers/unix/net_socket_posix.h | 37 | ||||
-rw-r--r-- | drivers/unix/os_unix.cpp | 265 | ||||
-rw-r--r-- | drivers/unix/os_unix.h | 74 | ||||
-rw-r--r-- | drivers/unix/rw_lock_posix.cpp | 93 | ||||
-rw-r--r-- | drivers/unix/rw_lock_posix.h | 62 | ||||
-rw-r--r-- | drivers/unix/syslog_logger.cpp | 8 | ||||
-rw-r--r-- | drivers/unix/syslog_logger.h | 8 | ||||
-rw-r--r-- | drivers/unix/thread_posix.cpp | 100 | ||||
-rw-r--r-- | drivers/unix/thread_posix.h | 44 |
16 files changed, 648 insertions, 756 deletions
diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp index 5b99a2f53f..d894ceba59 100644 --- a/drivers/unix/dir_access_unix.cpp +++ b/drivers/unix/dir_access_unix.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,29 +30,23 @@ #include "dir_access_unix.h" -#if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED) +#if defined(UNIX_ENABLED) -#include "core/list.h" #include "core/os/memory.h" -#include "core/print_string.h" +#include "core/os/os.h" +#include "core/string/print_string.h" +#include "core/templates/list.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> - -#ifndef ANDROID_ENABLED #include <sys/statvfs.h> -#endif #ifdef HAVE_MNTENT #include <mntent.h> #endif -DirAccess *DirAccessUnix::create_fs() { - return memnew(DirAccessUnix); -} - Error DirAccessUnix::list_dir_begin() { list_dir_end(); //close any previous dir opening! @@ -71,13 +65,13 @@ Error DirAccessUnix::list_dir_begin() { bool DirAccessUnix::file_exists(String p_file) { GLOBAL_LOCK_FUNCTION - if (p_file.is_rel_path()) { - p_file = current_dir.plus_file(p_file); + if (p_file.is_relative_path()) { + p_file = current_dir.path_join(p_file); } p_file = fix_path(p_file); - struct stat flags; + struct stat flags = {}; bool success = (stat(p_file.utf8().get_data(), &flags) == 0); if (success && S_ISDIR(flags.st_mode)) { @@ -90,35 +84,57 @@ bool DirAccessUnix::file_exists(String p_file) { bool DirAccessUnix::dir_exists(String p_dir) { GLOBAL_LOCK_FUNCTION - if (p_dir.is_rel_path()) { - p_dir = get_current_dir().plus_file(p_dir); + if (p_dir.is_relative_path()) { + p_dir = get_current_dir().path_join(p_dir); } p_dir = fix_path(p_dir); - struct stat flags; + struct stat flags = {}; bool success = (stat(p_dir.utf8().get_data(), &flags) == 0); return (success && S_ISDIR(flags.st_mode)); } +bool DirAccessUnix::is_readable(String p_dir) { + GLOBAL_LOCK_FUNCTION + + if (p_dir.is_relative_path()) { + p_dir = get_current_dir().path_join(p_dir); + } + + p_dir = fix_path(p_dir); + return (access(p_dir.utf8().get_data(), R_OK) == 0); +} + +bool DirAccessUnix::is_writable(String p_dir) { + GLOBAL_LOCK_FUNCTION + + if (p_dir.is_relative_path()) { + p_dir = get_current_dir().path_join(p_dir); + } + + p_dir = fix_path(p_dir); + return (access(p_dir.utf8().get_data(), W_OK) == 0); +} + uint64_t DirAccessUnix::get_modified_time(String p_file) { - if (p_file.is_rel_path()) { - p_file = current_dir.plus_file(p_file); + if (p_file.is_relative_path()) { + p_file = current_dir.path_join(p_file); } p_file = fix_path(p_file); - struct stat flags; + struct stat flags = {}; bool success = (stat(p_file.utf8().get_data(), &flags) == 0); if (success) { return flags.st_mtime; } else { ERR_FAIL_V(0); - }; + } return 0; -}; +} String DirAccessUnix::get_next() { if (!dir_stream) { @@ -140,9 +156,9 @@ String DirAccessUnix::get_next() { // known if it points to a directory. stat() will resolve the link // for us. if (entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK) { - String f = current_dir.plus_file(fname); + String f = current_dir.path_join(fname); - struct stat flags; + struct stat flags = {}; if (stat(f.utf8().get_data(), &flags) == 0) { _cisdir = S_ISDIR(flags.st_mode); } else { @@ -194,8 +210,11 @@ static bool _filter_drive(struct mntent *mnt) { #endif static void _get_drives(List<String> *list) { + // Add root. + list->push_back("/"); + #if defined(HAVE_MNTENT) && defined(X11_ENABLED) - // Check /etc/mtab for the list of mounted partitions + // Check /etc/mtab for the list of mounted partitions. FILE *mtab = setmntent("/etc/mtab", "r"); if (mtab) { struct mntent mnt; @@ -204,8 +223,9 @@ static void _get_drives(List<String> *list) { while (getmntent_r(mtab, &mnt, strings, sizeof(strings))) { if (mnt.mnt_dir != nullptr && _filter_drive(&mnt)) { // Avoid duplicates - if (!list->find(mnt.mnt_dir)) { - list->push_back(mnt.mnt_dir); + String name = String::utf8(mnt.mnt_dir); + if (!list->find(name)) { + list->push_back(name); } } } @@ -214,15 +234,17 @@ static void _get_drives(List<String> *list) { } #endif - // Add $HOME + // Add $HOME. const char *home = getenv("HOME"); if (home) { // Only add if it's not a duplicate - if (!list->find(home)) { - list->push_back(home); + String home_name = String::utf8(home); + if (!list->find(home_name)) { + list->push_back(home_name); } - // Check $HOME/.config/gtk-3.0/bookmarks + // Check GTK+3 bookmarks for both XDG locations (Documents, Downloads, etc.) + // and potential user-defined bookmarks. char path[1024]; snprintf(path, 1024, "%s/.config/gtk-3.0/bookmarks", home); FILE *fd = fopen(path, "r"); @@ -231,8 +253,8 @@ static void _get_drives(List<String> *list) { while (fgets(string, 1024, fd)) { // Parse only file:// links if (strncmp(string, "file://", 7) == 0) { - // Strip any unwanted edges on the strings and push_back if it's not a duplicate - String fpath = String(string + 7).strip_edges().split_spaces()[0].percent_decode(); + // Strip any unwanted edges on the strings and push_back if it's not a duplicate. + String fpath = String::utf8(string + 7).strip_edges().split_spaces()[0].uri_decode(); if (!list->find(fpath)) { list->push_back(fpath); } @@ -241,6 +263,12 @@ static void _get_drives(List<String> *list) { fclose(fd); } + + // Add Desktop dir. + String dpath = OS::get_singleton()->get_system_dir(OS::SystemDir::SYSTEM_DIR_DESKTOP); + if (dpath.length() > 0 && !list->find(dpath)) { + list->push_back(dpath); + } } list->sort(); @@ -262,6 +290,20 @@ String DirAccessUnix::get_drive(int p_drive) { return list[p_drive]; } +int DirAccessUnix::get_current_drive() { + int drive = 0; + int max_length = -1; + const String path = get_current_dir().to_lower(); + for (int i = 0; i < get_drive_count(); i++) { + const String d = get_drive(i).to_lower(); + if (max_length < d.length() && path.begins_with(d)) { + max_length = d.length(); + drive = i; + } + } + return drive; +} + bool DirAccessUnix::drives_are_shortcuts() { return true; } @@ -269,8 +311,8 @@ bool DirAccessUnix::drives_are_shortcuts() { Error DirAccessUnix::make_dir(String p_dir) { GLOBAL_LOCK_FUNCTION - if (p_dir.is_rel_path()) { - p_dir = get_current_dir().plus_file(p_dir); + if (p_dir.is_relative_path()) { + p_dir = get_current_dir().path_join(p_dir); } p_dir = fix_path(p_dir); @@ -280,11 +322,11 @@ Error DirAccessUnix::make_dir(String p_dir) { if (success) { return OK; - }; + } if (err == EEXIST) { return ERR_ALREADY_EXISTS; - }; + } return ERR_CANT_CREATE; } @@ -298,14 +340,14 @@ Error DirAccessUnix::change_dir(String p_dir) { String prev_dir; char real_current_dir_name[2048]; ERR_FAIL_COND_V(getcwd(real_current_dir_name, 2048) == nullptr, ERR_BUG); - if (prev_dir.parse_utf8(real_current_dir_name)) { + if (prev_dir.parse_utf8(real_current_dir_name) != OK) { prev_dir = real_current_dir_name; //no utf8, maybe latin? } // try_dir is the directory we are trying to change into String try_dir = ""; - if (p_dir.is_rel_path()) { - String next_dir = current_dir.plus_file(p_dir); + if (p_dir.is_relative_path()) { + String next_dir = current_dir.path_join(p_dir); next_dir = next_dir.simplify_path(); try_dir = next_dir; } else { @@ -318,7 +360,7 @@ Error DirAccessUnix::change_dir(String p_dir) { } String base = _get_root_path(); - if (base != String() && !try_dir.begins_with(base)) { + if (!base.is_empty() && !try_dir.begins_with(base)) { ERR_FAIL_COND_V(getcwd(real_current_dir_name, 2048) == nullptr, ERR_BUG); String new_dir; new_dir.parse_utf8(real_current_dir_name); @@ -334,9 +376,9 @@ Error DirAccessUnix::change_dir(String p_dir) { return OK; } -String DirAccessUnix::get_current_dir(bool p_include_drive) { +String DirAccessUnix::get_current_dir(bool p_include_drive) const { String base = _get_root_path(); - if (base != "") { + if (!base.is_empty()) { String bd = current_dir.replace_first(base, ""); if (bd.begins_with("/")) { return _get_root_string() + bd.substr(1, bd.length()); @@ -348,14 +390,14 @@ String DirAccessUnix::get_current_dir(bool p_include_drive) { } Error DirAccessUnix::rename(String p_path, String p_new_path) { - if (p_path.is_rel_path()) { - p_path = get_current_dir().plus_file(p_path); + if (p_path.is_relative_path()) { + p_path = get_current_dir().path_join(p_path); } p_path = fix_path(p_path); - if (p_new_path.is_rel_path()) { - p_new_path = get_current_dir().plus_file(p_new_path); + 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); @@ -364,13 +406,13 @@ Error DirAccessUnix::rename(String p_path, String p_new_path) { } Error DirAccessUnix::remove(String p_path) { - if (p_path.is_rel_path()) { - p_path = get_current_dir().plus_file(p_path); + if (p_path.is_relative_path()) { + p_path = get_current_dir().path_join(p_path); } p_path = fix_path(p_path); - struct stat flags; + struct stat flags = {}; if ((stat(p_path.utf8().get_data(), &flags) != 0)) { return FAILED; } @@ -382,19 +424,61 @@ Error DirAccessUnix::remove(String p_path) { } } -size_t DirAccessUnix::get_space_left() { -#ifndef NO_STATVFS +bool DirAccessUnix::is_link(String p_file) { + if (p_file.is_relative_path()) { + p_file = get_current_dir().path_join(p_file); + } + + p_file = fix_path(p_file); + + struct stat flags = {}; + if ((lstat(p_file.utf8().get_data(), &flags) != 0)) { + return FAILED; + } + + return S_ISLNK(flags.st_mode); +} + +String DirAccessUnix::read_link(String p_file) { + if (p_file.is_relative_path()) { + p_file = get_current_dir().path_join(p_file); + } + + p_file = fix_path(p_file); + + char buf[256]; + memset(buf, 0, 256); + ssize_t len = readlink(p_file.utf8().get_data(), buf, sizeof(buf)); + String link; + if (len > 0) { + link.parse_utf8(buf, len); + } + return link; +} + +Error DirAccessUnix::create_link(String p_source, String p_target) { + if (p_target.is_relative_path()) { + p_target = get_current_dir().path_join(p_target); + } + + p_source = fix_path(p_source); + p_target = fix_path(p_target); + + if (symlink(p_source.utf8().get_data(), p_target.utf8().get_data()) == 0) { + return OK; + } else { + return FAILED; + } +} + +uint64_t DirAccessUnix::get_space_left() { struct statvfs vfs; if (statvfs(current_dir.utf8().get_data(), &vfs) != 0) { return 0; - }; + } - return vfs.f_bfree * vfs.f_bsize; -#else - // FIXME: Implement this. - return 0; -#endif -}; + return (uint64_t)vfs.f_bavail * (uint64_t)vfs.f_frsize; +} String DirAccessUnix::get_filesystem_type() const { return ""; //TODO this should be implemented @@ -413,7 +497,7 @@ DirAccessUnix::DirAccessUnix() { // set current directory to an absolute path of the current directory char real_current_dir_name[2048]; ERR_FAIL_COND(getcwd(real_current_dir_name, 2048) == nullptr); - if (current_dir.parse_utf8(real_current_dir_name)) { + if (current_dir.parse_utf8(real_current_dir_name) != OK) { current_dir = real_current_dir_name; } @@ -424,4 +508,4 @@ DirAccessUnix::~DirAccessUnix() { list_dir_end(); } -#endif //posix_enabled +#endif // UNIX_ENABLED diff --git a/drivers/unix/dir_access_unix.h b/drivers/unix/dir_access_unix.h index 90f98d4705..4db24a27b9 100644 --- a/drivers/unix/dir_access_unix.h +++ b/drivers/unix/dir_access_unix.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,9 +31,9 @@ #ifndef DIR_ACCESS_UNIX_H #define DIR_ACCESS_UNIX_H -#if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED) +#if defined(UNIX_ENABLED) -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" #include <dirent.h> #include <sys/stat.h> @@ -41,49 +41,55 @@ #include <unistd.h> class DirAccessUnix : public DirAccess { - DIR *dir_stream; + DIR *dir_stream = nullptr; - static DirAccess *create_fs(); - - String current_dir; - bool _cisdir; - bool _cishidden; + bool _cisdir = false; + bool _cishidden = false; protected: + String current_dir; virtual String fix_unicode_name(const char *p_name) const { return String::utf8(p_name); } virtual bool is_hidden(const String &p_name); public: - virtual Error list_dir_begin(); ///< This starts dir listing - virtual String get_next(); - virtual bool current_is_dir() const; - virtual bool current_is_hidden() const; + virtual Error list_dir_begin() override; ///< This starts dir listing + virtual String get_next() override; + virtual bool current_is_dir() const override; + virtual bool current_is_hidden() const override; - virtual void list_dir_end(); ///< + virtual void list_dir_end() override; ///< - virtual int get_drive_count(); - virtual String get_drive(int p_drive); - virtual bool drives_are_shortcuts(); + virtual int get_drive_count() override; + virtual String get_drive(int p_drive) override; + virtual int get_current_drive() override; + virtual bool drives_are_shortcuts() override; - virtual Error change_dir(String p_dir); ///< can be relative or absolute, return false on success - virtual String get_current_dir(bool p_include_drive = true); ///< return current dir location - virtual Error make_dir(String p_dir); + virtual Error change_dir(String p_dir) override; ///< can be relative or absolute, return false on success + virtual String get_current_dir(bool p_include_drive = true) const override; ///< return current dir location + virtual Error make_dir(String p_dir) override; - virtual bool file_exists(String p_file); - virtual bool dir_exists(String p_dir); + virtual bool file_exists(String p_file) override; + virtual bool dir_exists(String p_dir) override; + virtual bool is_readable(String p_dir) override; + virtual bool is_writable(String p_dir) override; virtual uint64_t get_modified_time(String p_file); - virtual Error rename(String p_path, String p_new_path); - virtual Error remove(String p_path); + virtual Error rename(String p_path, String p_new_path) override; + virtual Error remove(String p_path) override; - virtual size_t get_space_left(); + virtual bool is_link(String p_file) override; + virtual String read_link(String p_file) override; + virtual Error create_link(String p_source, String p_target) override; - virtual String get_filesystem_type() const; + virtual uint64_t get_space_left() override; + + virtual String get_filesystem_type() const override; DirAccessUnix(); ~DirAccessUnix(); }; -#endif //UNIX ENABLED -#endif +#endif // UNIX_ENABLED + +#endif // DIR_ACCESS_UNIX_H diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp index 51c657007c..0b80fb1491 100644 --- a/drivers/unix/file_access_unix.cpp +++ b/drivers/unix/file_access_unix.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,24 +30,20 @@ #include "file_access_unix.h" -#if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED) +#if defined(UNIX_ENABLED) #include "core/os/os.h" -#include "core/print_string.h" +#include "core/string/print_string.h" +#include <errno.h> +#include <fcntl.h> #include <sys/stat.h> #include <sys/types.h> -#include <errno.h> - #if defined(UNIX_ENABLED) #include <unistd.h> #endif -#ifndef ANDROID_ENABLED -#include <sys/statvfs.h> -#endif - #ifdef MSVC #define S_ISREG(m) ((m)&_S_IFREG) #include <io.h> @@ -56,12 +52,6 @@ #define S_ISREG(m) ((m)&S_IFREG) #endif -#ifndef NO_FCNTL -#include <fcntl.h> -#else -#include <sys/ioctl.h> -#endif - void FileAccessUnix::check_errors() const { ERR_FAIL_COND_MSG(!f, "File must be opened before use."); @@ -70,11 +60,8 @@ void FileAccessUnix::check_errors() const { } } -Error FileAccessUnix::_open(const String &p_path, int p_mode_flags) { - if (f) { - fclose(f); - } - f = nullptr; +Error FileAccessUnix::open_internal(const String &p_path, int p_mode_flags) { + _close(); path_src = p_path; path = fix_path(p_path); @@ -99,7 +86,7 @@ Error FileAccessUnix::_open(const String &p_path, int p_mode_flags) { backend (unix-compatible mostly) supports utf8 encoding */ //printf("opening %s as %s\n", p_path.utf8().get_data(), path.utf8().get_data()); - struct stat st; + struct stat st = {}; int err = stat(path.utf8().get_data(), &st); if (!err) { switch (st.st_mode & S_IFMT) { @@ -111,7 +98,7 @@ Error FileAccessUnix::_open(const String &p_path, int p_mode_flags) { } } - if (is_backup_save_enabled() && (p_mode_flags & WRITE) && !(p_mode_flags & READ)) { + if (is_backup_save_enabled() && (p_mode_flags == WRITE)) { save_path = path; path = path + ".tmp"; } @@ -134,13 +121,8 @@ Error FileAccessUnix::_open(const String &p_path, int p_mode_flags) { int fd = fileno(f); if (fd != -1) { -#if defined(NO_FCNTL) - unsigned long par = 0; - ioctl(fd, FIOCLEX, &par); -#else int opts = fcntl(fd, F_GETFD); fcntl(fd, F_SETFD, opts | FD_CLOEXEC); -#endif } last_error = OK; @@ -148,7 +130,7 @@ Error FileAccessUnix::_open(const String &p_path, int p_mode_flags) { return OK; } -void FileAccessUnix::close() { +void FileAccessUnix::_close() { if (!f) { return; } @@ -160,7 +142,7 @@ void FileAccessUnix::close() { close_notification_func(path, flags); } - if (save_path != "") { + if (!save_path.is_empty()) { int rename_error = rename((save_path + ".tmp").utf8().get_data(), save_path.utf8().get_data()); if (rename_error && close_fail_notify) { @@ -184,11 +166,11 @@ String FileAccessUnix::get_path_absolute() const { return path; } -void FileAccessUnix::seek(size_t p_position) { +void FileAccessUnix::seek(uint64_t p_position) { ERR_FAIL_COND_MSG(!f, "File must be opened before use."); last_error = OK; - if (fseek(f, p_position, SEEK_SET)) { + if (fseeko(f, p_position, SEEK_SET)) { check_errors(); } } @@ -196,15 +178,15 @@ void FileAccessUnix::seek(size_t p_position) { void FileAccessUnix::seek_end(int64_t p_position) { ERR_FAIL_COND_MSG(!f, "File must be opened before use."); - if (fseek(f, p_position, SEEK_END)) { + if (fseeko(f, p_position, SEEK_END)) { check_errors(); } } -size_t FileAccessUnix::get_position() const { +uint64_t FileAccessUnix::get_position() const { ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use."); - long pos = ftell(f); + int64_t pos = ftello(f); if (pos < 0) { check_errors(); ERR_FAIL_V(0); @@ -212,15 +194,15 @@ size_t FileAccessUnix::get_position() const { return pos; } -size_t FileAccessUnix::get_len() const { +uint64_t FileAccessUnix::get_length() const { ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use."); - long pos = ftell(f); + int64_t pos = ftello(f); ERR_FAIL_COND_V(pos < 0, 0); - ERR_FAIL_COND_V(fseek(f, 0, SEEK_END), 0); - long size = ftell(f); + ERR_FAIL_COND_V(fseeko(f, 0, SEEK_END), 0); + int64_t size = ftello(f); ERR_FAIL_COND_V(size < 0, 0); - ERR_FAIL_COND_V(fseek(f, pos, SEEK_SET), 0); + ERR_FAIL_COND_V(fseeko(f, pos, SEEK_SET), 0); return size; } @@ -239,12 +221,14 @@ uint8_t FileAccessUnix::get_8() const { return b; } -int FileAccessUnix::get_buffer(uint8_t *p_dst, int p_length) const { +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_COND_V_MSG(!f, -1, "File must be opened before use."); - int read = fread(p_dst, 1, p_length, f); + + uint64_t read = fread(p_dst, 1, p_length, f); check_errors(); return read; -}; +} Error FileAccessUnix::get_error() const { return last_error; @@ -260,15 +244,15 @@ void FileAccessUnix::store_8(uint8_t p_dest) { ERR_FAIL_COND(fwrite(&p_dest, 1, 1, f) != 1); } -void FileAccessUnix::store_buffer(const uint8_t *p_src, int p_length) { +void FileAccessUnix::store_buffer(const uint8_t *p_src, uint64_t p_length) { ERR_FAIL_COND_MSG(!f, "File must be opened before use."); - ERR_FAIL_COND(!p_src); - ERR_FAIL_COND((int)fwrite(p_src, 1, p_length, f) != p_length); + ERR_FAIL_COND(!p_src && p_length > 0); + ERR_FAIL_COND(fwrite(p_src, 1, p_length, f) != p_length); } bool FileAccessUnix::file_exists(const String &p_path) { int err; - struct stat st; + struct stat st = {}; String filename = fix_path(p_path); // Does the name exist at all? @@ -283,8 +267,9 @@ bool FileAccessUnix::file_exists(const String &p_path) { return false; } #else - if (_access(filename.utf8().get_data(), 4) == -1) + if (_access(filename.utf8().get_data(), 4) == -1) { return false; + } #endif // See if this is a regular file @@ -299,26 +284,27 @@ bool FileAccessUnix::file_exists(const String &p_path) { uint64_t FileAccessUnix::_get_modified_time(const String &p_file) { String file = fix_path(p_file); - struct stat flags; + struct stat flags = {}; int err = stat(file.utf8().get_data(), &flags); if (!err) { return flags.st_mtime; } else { - ERR_FAIL_V_MSG(0, "Failed to get modified time for: " + p_file + "."); - }; + print_verbose("Failed to get modified time for: " + p_file + ""); + return 0; + } } uint32_t FileAccessUnix::_get_unix_permissions(const String &p_file) { String file = fix_path(p_file); - struct stat flags; + struct stat flags = {}; int err = stat(file.utf8().get_data(), &flags); if (!err) { return flags.st_mode & 0x7FF; //only permissions } else { ERR_FAIL_V_MSG(0, "Failed to get unix permissions for: " + p_file + "."); - }; + } } Error FileAccessUnix::_set_unix_permissions(const String &p_file, uint32_t p_permissions) { @@ -332,14 +318,10 @@ Error FileAccessUnix::_set_unix_permissions(const String &p_file, uint32_t p_per return FAILED; } -FileAccess *FileAccessUnix::create_libc() { - return memnew(FileAccessUnix); -} - CloseNotificationFunc FileAccessUnix::close_notification_func = nullptr; FileAccessUnix::~FileAccessUnix() { - close(); + _close(); } -#endif +#endif // UNIX_ENABLED diff --git a/drivers/unix/file_access_unix.h b/drivers/unix/file_access_unix.h index 9fe43a2554..8c9afe75e7 100644 --- a/drivers/unix/file_access_unix.h +++ b/drivers/unix/file_access_unix.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,12 +31,12 @@ #ifndef FILE_ACCESS_UNIX_H #define FILE_ACCESS_UNIX_H -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/os/memory.h" #include <stdio.h> -#if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED) +#if defined(UNIX_ENABLED) typedef void (*CloseNotificationFunc)(const String &p_file, int p_flags); @@ -49,43 +49,43 @@ class FileAccessUnix : public FileAccess { String path; String path_src; - static FileAccess *create_libc(); + void _close(); public: static CloseNotificationFunc close_notification_func; - virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file - virtual void close(); ///< close a file - virtual bool is_open() const; ///< true when file is open + 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 - virtual String get_path() const; /// returns the path for the current open file - virtual String get_path_absolute() const; /// returns the absolute path for the current open file + virtual String get_path() const override; /// returns the path for the current open file + virtual String get_path_absolute() const override; /// returns the absolute path for the current open file - virtual void seek(size_t p_position); ///< seek to a given position - virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file - virtual size_t get_position() const; ///< get position in the file - virtual size_t get_len() const; ///< get size of the file + virtual void seek(uint64_t p_position) override; ///< seek to a given position + virtual void seek_end(int64_t p_position = 0) override; ///< seek from the end of file + virtual uint64_t get_position() const override; ///< get position in the file + virtual uint64_t get_length() const override; ///< get size of the file - virtual bool eof_reached() const; ///< reading passed EOF + virtual bool eof_reached() const override; ///< reading passed EOF - virtual uint8_t get_8() const; ///< get a byte - virtual int get_buffer(uint8_t *p_dst, int p_length) const; + 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; ///< get last error + virtual Error get_error() const override; ///< get last error - virtual void flush(); - virtual void store_8(uint8_t p_dest); ///< store a byte - virtual void store_buffer(const uint8_t *p_src, int p_length); ///< store an array of bytes + virtual void flush() override; + virtual void store_8(uint8_t p_dest) 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 file_exists(const String &p_path); ///< return true if a file exists + virtual bool file_exists(const String &p_path) override; ///< return true if a file exists - virtual uint64_t _get_modified_time(const String &p_file); - virtual uint32_t _get_unix_permissions(const String &p_file); - virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions); + virtual uint64_t _get_modified_time(const String &p_file) override; + virtual uint32_t _get_unix_permissions(const String &p_file) override; + virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override; FileAccessUnix() {} virtual ~FileAccessUnix(); }; -#endif -#endif +#endif // UNIX_ENABLED + +#endif // FILE_ACCESS_UNIX_H diff --git a/drivers/unix/ip_unix.cpp b/drivers/unix/ip_unix.cpp index 05eedccc1d..0dc2efedc1 100644 --- a/drivers/unix/ip_unix.cpp +++ b/drivers/unix/ip_unix.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -36,24 +36,12 @@ #ifdef WINDOWS_ENABLED #include <stdio.h> -#include <winsock2.h> -// Needs to be included after winsocks2.h +#define WIN32_LEAN_AND_MEAN #include <windows.h> +#include <winsock2.h> #include <ws2tcpip.h> #ifndef UWP_ENABLED -#if defined(__MINGW32__) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 4) -// MinGW-w64 on Ubuntu 12.04 (our Travis build env) has bugs in this code where -// some includes are missing in dependencies of iphlpapi.h for WINVER >= 0x0600 (Vista). -// We don't use this Vista code for now, so working it around by disabling it. -// MinGW-w64 >= 4.0 seems to be better judging by its headers. -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 // Windows XP, disable Vista API -#include <iphlpapi.h> -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x0600 // Re-enable Vista API -#else #include <iphlpapi.h> -#endif // MINGW hack #endif #else // UNIX #include <netdb.h> @@ -75,8 +63,8 @@ #include <net/if.h> // Order is important on OpenBSD, leave as last #endif -static IP_Address _sockaddr2ip(struct sockaddr *p_addr) { - IP_Address ip; +static IPAddress _sockaddr2ip(struct sockaddr *p_addr) { + IPAddress ip; if (p_addr->sa_family == AF_INET) { struct sockaddr_in *addr = (struct sockaddr_in *)p_addr; @@ -84,14 +72,14 @@ static IP_Address _sockaddr2ip(struct sockaddr *p_addr) { } else if (p_addr->sa_family == AF_INET6) { struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr; ip.set_ipv6(addr6->sin6_addr.s6_addr); - }; + } return ip; -}; +} -IP_Address IP_Unix::_resolve_hostname(const String &p_hostname, Type p_type) { +void IPUnix::_resolve_hostname(List<IPAddress> &r_addresses, const String &p_hostname, Type p_type) const { struct addrinfo hints; - struct addrinfo *result; + struct addrinfo *result = nullptr; memset(&hints, 0, sizeof(struct addrinfo)); if (p_type == TYPE_IPV4) { @@ -102,35 +90,45 @@ IP_Address IP_Unix::_resolve_hostname(const String &p_hostname, Type p_type) { } else { hints.ai_family = AF_UNSPEC; hints.ai_flags = AI_ADDRCONFIG; - }; + } hints.ai_flags &= ~AI_NUMERICHOST; int s = getaddrinfo(p_hostname.utf8().get_data(), nullptr, &hints, &result); if (s != 0) { - ERR_PRINT("getaddrinfo failed! Cannot resolve hostname."); - return IP_Address(); - }; + print_verbose("getaddrinfo failed! Cannot resolve hostname."); + return; + } if (result == nullptr || result->ai_addr == nullptr) { - ERR_PRINT("Invalid response from getaddrinfo"); + print_verbose("Invalid response from getaddrinfo"); if (result) { freeaddrinfo(result); } - return IP_Address(); - }; + return; + } - IP_Address ip = _sockaddr2ip(result->ai_addr); + struct addrinfo *next = result; - freeaddrinfo(result); + do { + if (next->ai_addr == nullptr) { + next = next->ai_next; + continue; + } + IPAddress ip = _sockaddr2ip(next->ai_addr); + if (ip.is_valid() && !r_addresses.find(ip)) { + r_addresses.push_back(ip); + } + next = next->ai_next; + } while (next); - return ip; + freeaddrinfo(result); } #if defined(WINDOWS_ENABLED) #if defined(UWP_ENABLED) -void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const { +void IPUnix::get_local_interfaces(HashMap<String, Interface_Info> *r_interfaces) const { using namespace Windows::Networking; using namespace Windows::Networking::Connectivity; @@ -140,11 +138,12 @@ void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) co for (int i = 0; i < hostnames->Size; i++) { auto hostname = hostnames->GetAt(i); - if (hostname->Type != HostNameType::Ipv4 && hostname->Type != HostNameType::Ipv6) + if (hostname->Type != HostNameType::Ipv4 && hostname->Type != HostNameType::Ipv6) { continue; + } String name = hostname->RawName->Data(); - Map<String, Interface_Info>::Element *E = r_interfaces->find(name); + HashMap<String, Interface_Info>::Element *E = r_interfaces->find(name); if (!E) { Interface_Info info; info.name = name; @@ -156,14 +155,14 @@ void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) co Interface_Info &info = E->get(); - IP_Address ip = IP_Address(hostname->CanonicalName->Data()); + IPAddress ip = IPAddress(hostname->CanonicalName->Data()); info.ip_addresses.push_front(ip); } } #else -void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const { +void IPUnix::get_local_interfaces(HashMap<String, Interface_Info> *r_interfaces) const { ULONG buf_size = 1024; IP_ADAPTER_ADDRESSES *addrs; @@ -173,14 +172,14 @@ void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) co 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; @@ -193,25 +192,27 @@ void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) co IP_ADAPTER_UNICAST_ADDRESS *address = adapter->FirstUnicastAddress; while (address != nullptr) { int family = address->Address.lpSockaddr->sa_family; - if (family != AF_INET && family != AF_INET6) + 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) + if (info.ip_addresses.size() > 0) { r_interfaces->insert(info.name, info); - }; + } + } memfree(addrs); -}; +} #endif #else // UNIX -void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const { +void IPUnix::get_local_interfaces(HashMap<String, Interface_Info> *r_interfaces) const { struct ifaddrs *ifAddrStruct = nullptr; struct ifaddrs *ifa = nullptr; int family; @@ -229,7 +230,7 @@ void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) co continue; } - Map<String, Interface_Info>::Element *E = r_interfaces->find(ifa->ifa_name); + HashMap<String, Interface_Info>::Iterator E = r_interfaces->find(ifa->ifa_name); if (!E) { Interface_Info info; info.name = ifa->ifa_name; @@ -239,7 +240,7 @@ void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) co ERR_CONTINUE(!E); } - Interface_Info &info = E->get(); + Interface_Info &info = E->value; info.ip_addresses.push_front(_sockaddr2ip(ifa->ifa_addr)); } @@ -249,15 +250,15 @@ void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) co } #endif -void IP_Unix::make_default() { +void IPUnix::make_default() { _create = _create_unix; } -IP *IP_Unix::_create_unix() { - return memnew(IP_Unix); +IP *IPUnix::_create_unix() { + return memnew(IPUnix); } -IP_Unix::IP_Unix() { +IPUnix::IPUnix() { } #endif diff --git a/drivers/unix/ip_unix.h b/drivers/unix/ip_unix.h index 7497f64a53..798d02095c 100644 --- a/drivers/unix/ip_unix.h +++ b/drivers/unix/ip_unix.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -35,19 +35,20 @@ #if defined(UNIX_ENABLED) || defined(WINDOWS_ENABLED) -class IP_Unix : public IP { - GDCLASS(IP_Unix, IP); +class IPUnix : public IP { + GDCLASS(IPUnix, IP); - virtual IP_Address _resolve_hostname(const String &p_hostname, IP::Type p_type) override; + virtual void _resolve_hostname(List<IPAddress> &r_addresses, const String &p_hostname, Type p_type = TYPE_ANY) const override; static IP *_create_unix(); public: - virtual void get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const override; + virtual void get_local_interfaces(HashMap<String, Interface_Info> *r_interfaces) const override; static void make_default(); - IP_Unix(); + IPUnix(); }; #endif + #endif // IP_UNIX_H diff --git a/drivers/unix/net_socket_posix.cpp b/drivers/unix/net_socket_posix.cpp index 186804dbb1..c6b327eeee 100644 --- a/drivers/unix/net_socket_posix.cpp +++ b/drivers/unix/net_socket_posix.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,32 +30,30 @@ #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) #include <errno.h> +#include <fcntl.h> #include <netdb.h> +#include <netinet/in.h> +#include <netinet/tcp.h> #include <poll.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/ioctl.h> +#include <sys/socket.h> #include <sys/types.h> #include <unistd.h> -#ifndef NO_FCNTL -#include <fcntl.h> -#else -#include <sys/ioctl.h> -#endif -#include <netinet/in.h> -#include <sys/socket.h> -#ifdef JAVASCRIPT_ENABLED +#ifdef WEB_ENABLED #include <arpa/inet.h> #endif -#include <netinet/tcp.h> - // BSD calls this flag IPV6_JOIN_GROUP #if !defined(IPV6_ADD_MEMBERSHIP) && defined(IPV6_JOIN_GROUP) #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP @@ -93,9 +91,9 @@ #define SIO_UDP_NETRESET _WSAIOW(IOC_VENDOR, 15) #endif -#endif +#endif // UNIX_ENABLED -size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const IP_Address &p_ip, uint16_t p_port, IP::Type p_ip_type) { +size_t NetSocketPosix::_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 @@ -106,7 +104,7 @@ size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const addr6->sin6_family = AF_INET6; addr6->sin6_port = htons(p_port); if (p_ip.is_valid()) { - copymem(&addr6->sin6_addr.s6_addr, p_ip.get_ipv6(), 16); + memcpy(&addr6->sin6_addr.s6_addr, p_ip.get_ipv6(), 16); } else { addr6->sin6_addr = in6addr_any; } @@ -121,7 +119,7 @@ size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const addr4->sin_port = htons(p_port); // short, network byte order if (p_ip.is_valid()) { - copymem(&addr4->sin_addr.s_addr, p_ip.get_ipv4(), 4); + memcpy(&addr4->sin_addr.s_addr, p_ip.get_ipv4(), 4); } else { addr4->sin_addr.s_addr = INADDR_ANY; } @@ -130,19 +128,24 @@ size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const } } -void NetSocketPosix::_set_ip_port(struct sockaddr_storage *p_addr, IP_Address &r_ip, uint16_t &r_port) { +void NetSocketPosix::_set_ip_port(struct sockaddr_storage *p_addr, IPAddress *r_ip, uint16_t *r_port) { if (p_addr->ss_family == AF_INET) { struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr; - r_ip.set_ipv4((uint8_t *)&(addr4->sin_addr.s_addr)); - - r_port = ntohs(addr4->sin_port); - + if (r_ip) { + r_ip->set_ipv4((uint8_t *)&(addr4->sin_addr.s_addr)); + } + if (r_port) { + *r_port = ntohs(addr4->sin_port); + } } else if (p_addr->ss_family == AF_INET6) { struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr; - r_ip.set_ipv6(addr6->sin6_addr.s6_addr); - - r_port = ntohs(addr6->sin6_port); - }; + if (r_ip) { + r_ip->set_ipv6(addr6->sin6_addr.s6_addr); + } + if (r_port) { + *r_port = ntohs(addr6->sin6_port); + } + } } NetSocket *NetSocketPosix::_create_func() { @@ -176,8 +179,8 @@ NetSocketPosix::~NetSocketPosix() { close(); } -// Silent a warning reported in #27594 - +// Silence a warning reported in GH-27594. +// EAGAIN and EWOULDBLOCK have the same value on most platforms, but it's not guaranteed. #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wlogical-op" @@ -186,13 +189,21 @@ NetSocketPosix::~NetSocketPosix() { NetSocketPosix::NetError NetSocketPosix::_get_socket_error() const { #if defined(WINDOWS_ENABLED) int err = WSAGetLastError(); - - if (err == WSAEISCONN) + if (err == WSAEISCONN) { return ERR_NET_IS_CONNECTED; - if (err == WSAEINPROGRESS || err == WSAEALREADY) + } + if (err == WSAEINPROGRESS || err == WSAEALREADY) { return ERR_NET_IN_PROGRESS; - if (err == WSAEWOULDBLOCK) + } + 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; + } print_verbose("Socket error: " + itos(err)); return ERR_NET_OTHER; #else @@ -205,6 +216,12 @@ NetSocketPosix::NetError NetSocketPosix::_get_socket_error() const { if (errno == EAGAIN || errno == EWOULDBLOCK) { return ERR_NET_WOULD_BLOCK; } + if (errno == EADDRINUSE || errno == EINVAL || errno == EADDRNOTAVAIL) { + return ERR_NET_ADDRESS_INVALID_OR_UNAVAILABLE; + } + if (errno == EACCES) { + return ERR_NET_UNAUTHORIZED; + } print_verbose("Socket error: " + itos(errno)); return ERR_NET_OTHER; #endif @@ -214,7 +231,7 @@ NetSocketPosix::NetError NetSocketPosix::_get_socket_error() const { #pragma GCC diagnostic pop #endif -bool NetSocketPosix::_can_use_ip(const IP_Address &p_ip, const bool p_for_bind) const { +bool NetSocketPosix::_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()) { @@ -225,7 +242,7 @@ bool NetSocketPosix::_can_use_ip(const IP_Address &p_ip, const bool p_for_bind) return !(_ip_type != IP::TYPE_ANY && !p_ip.is_wildcard() && _ip_type != type); } -_FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IP_Address p_ip, String p_if_name, bool p_add) { +_FORCE_INLINE_ Error NetSocketPosix::_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); @@ -235,12 +252,12 @@ _FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IP_Address p_ip, St int level = type == IP::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6; int ret = -1; - IP_Address if_ip; + IPAddress if_ip; uint32_t if_v6id = 0; - Map<String, IP::Interface_Info> if_info; + HashMap<String, IP::Interface_Info> if_info; IP::get_singleton()->get_local_interfaces(&if_info); - for (Map<String, IP::Interface_Info>::Element *E = if_info.front(); E; E = E->next()) { - IP::Interface_Info &c = E->get(); + for (KeyValue<String, IP::Interface_Info> &E : if_info) { + IP::Interface_Info &c = E.value; if (c.name != p_if_name) { continue; } @@ -250,11 +267,11 @@ _FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IP_Address p_ip, St break; // IPv6 uses index. } - for (List<IP_Address>::Element *F = c.ip_addresses.front(); F; F = F->next()) { - if (!F->get().is_ipv4()) { + for (const IPAddress &F : c.ip_addresses) { + if (!F.is_ipv4()) { continue; // Wrong IP type } - if_ip = F->get(); + if_ip = F; break; } break; @@ -264,13 +281,13 @@ _FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IP_Address p_ip, St ERR_FAIL_COND_V(!if_ip.is_valid(), ERR_INVALID_PARAMETER); struct ip_mreq greq; int sock_opt = p_add ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP; - copymem(&greq.imr_multiaddr, p_ip.get_ipv4(), 4); - copymem(&greq.imr_interface, if_ip.get_ipv4(), 4); + memcpy(&greq.imr_multiaddr, p_ip.get_ipv4(), 4); + memcpy(&greq.imr_interface, if_ip.get_ipv4(), 4); ret = setsockopt(_sock, level, sock_opt, (const char *)&greq, sizeof(greq)); } else { struct ipv6_mreq greq; int sock_opt = p_add ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP; - copymem(&greq.ipv6mr_multiaddr, p_ip.get_ipv6(), 16); + memcpy(&greq.ipv6mr_multiaddr, p_ip.get_ipv6(), 16); greq.ipv6mr_interface = if_v6id; ret = setsockopt(_sock, level, sock_opt, (const char *)&greq, sizeof(greq)); } @@ -290,14 +307,9 @@ void NetSocketPosix::_set_socket(SOCKET_TYPE p_sock, IP::Type p_ip_type, bool p_ void NetSocketPosix::_set_close_exec_enabled(bool p_enabled) { #ifndef WINDOWS_ENABLED // Enable close on exec to avoid sharing with subprocesses. Off by default on Windows. -#if defined(NO_FCNTL) - unsigned long par = p_enabled ? 1 : 0; - SOCK_IOCTL(_sock, FIOCLEX, &par); -#else int opts = fcntl(_sock, F_GETFD); fcntl(_sock, F_SETFD, opts | FD_CLOEXEC); #endif -#endif } Error NetSocketPosix::open(Type p_sock_type, IP::Type &ip_type) { @@ -306,8 +318,9 @@ Error NetSocketPosix::open(Type p_sock_type, IP::Type &ip_type) { #if defined(__OpenBSD__) // OpenBSD does not support dual stacking, fallback to IPv4 only. - if (ip_type == IP::TYPE_ANY) + if (ip_type == IP::TYPE_ANY) { ip_type = IP::TYPE_IPV4; + } #endif int family = ip_type == IP::TYPE_IPV4 ? AF_INET : AF_INET6; @@ -348,11 +361,11 @@ Error NetSocketPosix::open(Type p_sock_type, IP::Type &ip_type) { // 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 behaviour on Windows"); + 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 behaviour on Windows"); + print_verbose("Unable to turn off UDP WSAENETRESET behavior on Windows"); } } #endif @@ -376,7 +389,7 @@ void NetSocketPosix::close() { _is_stream = false; } -Error NetSocketPosix::bind(IP_Address p_addr, uint16_t p_port) { +Error NetSocketPosix::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); @@ -384,8 +397,8 @@ Error NetSocketPosix::bind(IP_Address p_addr, uint16_t p_port) { size_t addr_size = _set_addr_storage(&addr, p_addr, p_port, _ip_type); if (::bind(_sock, (struct sockaddr *)&addr, addr_size) != 0) { - _get_socket_error(); - print_verbose("Failed to bind socket."); + NetError err = _get_socket_error(); + print_verbose("Failed to bind socket. Error: " + itos(err)); close(); return ERR_UNAVAILABLE; } @@ -401,12 +414,12 @@ Error NetSocketPosix::listen(int p_max_pending) { print_verbose("Failed to listen from socket."); close(); return FAILED; - }; + } return OK; } -Error NetSocketPosix::connect_to_host(IP_Address p_host, uint16_t p_port) { +Error NetSocketPosix::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); @@ -446,8 +459,8 @@ Error NetSocketPosix::poll(PollType p_type, int p_timeout) const { FD_ZERO(&wr); FD_ZERO(&ex); FD_SET(_sock, &ex); - struct timeval timeout = { p_timeout, 0 }; - // For blocking operation, pass nullptr timeout pointer to select. + 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. @@ -475,8 +488,9 @@ Error NetSocketPosix::poll(PollType p_type, int p_timeout) const { return FAILED; } - if (ret == 0) + if (ret == 0) { return ERR_BUSY; + } if (FD_ISSET(_sock, &ex)) { _get_socket_error(); @@ -484,10 +498,12 @@ Error NetSocketPosix::poll(PollType p_type, int p_timeout) const { return FAILED; } - if (rdp && FD_ISSET(_sock, rdp)) + if (rdp && FD_ISSET(_sock, rdp)) { ready = true; - if (wrp && FD_ISSET(_sock, wrp)) + } + if (wrp && FD_ISSET(_sock, wrp)) { ready = true; + } return ready ? OK : ERR_BUSY; #else @@ -540,7 +556,7 @@ 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, IP_Address &r_ip, uint16_t &r_port, bool p_peek) { +Error NetSocketPosix::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; @@ -597,7 +613,7 @@ 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, IP_Address p_ip, uint16_t p_port) { +Error NetSocketPosix::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; @@ -635,7 +651,7 @@ void NetSocketPosix::set_blocking_enabled(bool p_enabled) { ERR_FAIL_COND(!is_open()); int ret = 0; -#if defined(WINDOWS_ENABLED) || defined(NO_FCNTL) +#if defined(WINDOWS_ENABLED) unsigned long par = p_enabled ? 0 : 1; ret = SOCK_IOCTL(_sock, FIONBIO, &par); #else @@ -716,7 +732,21 @@ int NetSocketPosix::get_available_bytes() const { return len; } -Ref<NetSocket> NetSocketPosix::accept(IP_Address &r_ip, uint16_t &r_port) { +Error NetSocketPosix::get_socket_address(IPAddress *r_ip, uint16_t *r_port) const { + ERR_FAIL_COND_V(!is_open(), FAILED); + + struct sockaddr_storage saddr; + socklen_t len = sizeof(saddr); + if (getsockname(_sock, (struct sockaddr *)&saddr, &len) != 0) { + _get_socket_error(); + print_verbose("Error when reading local socket address."); + return FAILED; + } + _set_ip_port(&saddr, r_ip, r_port); + return OK; +} + +Ref<NetSocket> NetSocketPosix::accept(IPAddress &r_ip, uint16_t &r_port) { Ref<NetSocket> out; ERR_FAIL_COND_V(!is_open(), out); @@ -729,7 +759,7 @@ Ref<NetSocket> NetSocketPosix::accept(IP_Address &r_ip, uint16_t &r_port) { return out; } - _set_ip_port(&their_addr, r_ip, r_port); + _set_ip_port(&their_addr, &r_ip, &r_port); NetSocketPosix *ns = memnew(NetSocketPosix); ns->_set_socket(fd, _ip_type, _is_stream); @@ -737,11 +767,12 @@ Ref<NetSocket> NetSocketPosix::accept(IP_Address &r_ip, uint16_t &r_port) { return Ref<NetSocket>(ns); } -Error NetSocketPosix::join_multicast_group(const IP_Address &p_multi_address, String p_if_name) { +Error NetSocketPosix::join_multicast_group(const IPAddress &p_multi_address, String p_if_name) { return _change_multicast_group(p_multi_address, p_if_name, true); } -Error NetSocketPosix::leave_multicast_group(const IP_Address &p_multi_address, String p_if_name) { +Error NetSocketPosix::leave_multicast_group(const IPAddress &p_multi_address, String p_if_name) { return _change_multicast_group(p_multi_address, p_if_name, false); } -#endif + +#endif // UNIX_SOCKET_UNAVAILABLE diff --git a/drivers/unix/net_socket_posix.h b/drivers/unix/net_socket_posix.h index 8cefb6544e..5558114cb1 100644 --- a/drivers/unix/net_socket_posix.h +++ b/drivers/unix/net_socket_posix.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef NET_SOCKET_UNIX_H -#define NET_SOCKET_UNIX_H +#ifndef NET_SOCKET_POSIX_H +#define NET_SOCKET_POSIX_H #include "core/io/net_socket.h" @@ -54,39 +54,42 @@ private: ERR_NET_WOULD_BLOCK, ERR_NET_IS_CONNECTED, ERR_NET_IN_PROGRESS, - ERR_NET_OTHER + ERR_NET_ADDRESS_INVALID_OR_UNAVAILABLE, + ERR_NET_UNAUTHORIZED, + ERR_NET_OTHER, }; NetError _get_socket_error() const; void _set_socket(SOCKET_TYPE p_sock, IP::Type p_ip_type, bool p_is_stream); - _FORCE_INLINE_ Error _change_multicast_group(IP_Address p_ip, String p_if_name, bool p_add); + _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); protected: static NetSocket *_create_func(); - bool _can_use_ip(const IP_Address &p_ip, const bool p_for_bind) const; + bool _can_use_ip(const IPAddress &p_ip, const bool p_for_bind) const; public: static void make_default(); static void cleanup(); - static void _set_ip_port(struct sockaddr_storage *p_addr, IP_Address &r_ip, uint16_t &r_port); - static size_t _set_addr_storage(struct sockaddr_storage *p_addr, const IP_Address &p_ip, uint16_t p_port, IP::Type p_ip_type); + static 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(IP_Address p_addr, uint16_t p_port); + virtual Error bind(IPAddress p_addr, uint16_t p_port); virtual Error listen(int p_max_pending); - virtual Error connect_to_host(IP_Address p_host, uint16_t p_port); + 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, IP_Address &r_ip, uint16_t &r_port, bool p_peek = false); + 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, IP_Address p_ip, uint16_t p_port); - virtual Ref<NetSocket> accept(IP_Address &r_ip, uint16_t &r_port); + 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 bool is_open() const; virtual int get_available_bytes() const; + virtual Error get_socket_address(IPAddress *r_ip, uint16_t *r_port) const; virtual Error set_broadcasting_enabled(bool p_enabled); virtual void set_blocking_enabled(bool p_enabled); @@ -94,11 +97,11 @@ public: 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 IP_Address &p_multi_address, String p_if_name); - virtual Error leave_multicast_group(const IP_Address &p_multi_address, String p_if_name); + virtual Error join_multicast_group(const IPAddress &p_multi_address, String p_if_name); + virtual Error leave_multicast_group(const IPAddress &p_multi_address, String p_if_name); NetSocketPosix(); ~NetSocketPosix(); }; -#endif +#endif // NET_SOCKET_POSIX_H diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index 96c338f86b..161706489f 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -32,14 +32,12 @@ #ifdef UNIX_ENABLED +#include "core/config/project_settings.h" #include "core/debugger/engine_debugger.h" #include "core/debugger/script_debugger.h" -#include "core/os/thread_dummy.h" -#include "core/project_settings.h" #include "drivers/unix/dir_access_unix.h" #include "drivers/unix/file_access_unix.h" #include "drivers/unix/net_socket_posix.h" -#include "drivers/unix/rw_lock_posix.h" #include "drivers/unix/thread_posix.h" #include "servers/rendering_server.h" @@ -53,7 +51,6 @@ #include <sys/sysctl.h> #endif -#include <assert.h> #include <dlfcn.h> #include <errno.h> #include <poll.h> @@ -64,8 +61,24 @@ #include <string.h> #include <sys/time.h> #include <sys/wait.h> +#include <time.h> #include <unistd.h> +#if defined(MACOS_ENABLED) || (defined(__ANDROID_API__) && __ANDROID_API__ >= 28) +// Random location for getentropy. Fitting. +#include <sys/random.h> +#define UNIX_GET_ENTROPY +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || (defined(__GLIBC_MINOR__) && (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 26)) +// In <unistd.h>. +// One day... (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 700) +// https://publications.opengroup.org/standards/unix/c211 +#define UNIX_GET_ENTROPY +#endif + +#if !defined(UNIX_GET_ENTROPY) && !defined(NO_URANDOM) +#include <fcntl.h> +#endif + /// Clock Setup function (used by get_ticks_usec) static uint64_t _clock_start = 0; #if defined(__APPLE__) @@ -78,7 +91,7 @@ static void _setup_clock() { _clock_start = mach_absolute_time() * _clock_scale; } #else -#if defined(CLOCK_MONOTONIC_RAW) && !defined(JAVASCRIPT_ENABLED) // This is a better clock on Linux. +#if defined(CLOCK_MONOTONIC_RAW) && !defined(WEB_ENABLED) // This is a better clock on Linux. #define GODOT_CLOCK CLOCK_MONOTONIC_RAW #else #define GODOT_CLOCK CLOCK_MONOTONIC @@ -90,10 +103,6 @@ static void _setup_clock() { } #endif -void OS_Unix::debug_break() { - assert(false); -}; - static void handle_interrupt(int sig) { if (!EngineDebugger::is_active()) { return; @@ -117,25 +126,17 @@ int OS_Unix::unix_initialize_audio(int p_audio_driver) { } void OS_Unix::initialize_core() { -#ifdef NO_THREADS - ThreadDummy::make_default(); - RWLockDummy::make_default(); -#else - ThreadPosix::make_default(); - RWLockPosix::make_default(); -#endif + init_thread_posix(); + FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_RESOURCES); FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_USERDATA); FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_FILESYSTEM); - //FileAccessBufferedFA<FileAccessUnix>::make_default(); DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_RESOURCES); DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_USERDATA); DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_FILESYSTEM); -#ifndef NO_NETWORK NetSocketPosix::make_default(); - IP_Unix::make_default(); -#endif + IPUnix::make_default(); _setup_clock(); } @@ -144,8 +145,8 @@ void OS_Unix::finalize_core() { NetSocketPosix::cleanup(); } -void OS_Unix::alert(const String &p_alert, const String &p_title) { - fprintf(stderr, "ERROR: %s\n", p_alert.utf8().get_data()); +Vector<String> OS_Unix::get_video_adapter_driver_info() const { + return Vector<String>(); } String OS_Unix::get_stdin_string(bool p_block) { @@ -159,25 +160,59 @@ String OS_Unix::get_stdin_string(bool p_block) { return ""; } +Error OS_Unix::get_entropy(uint8_t *r_buffer, int p_bytes) { +#if defined(UNIX_GET_ENTROPY) + int left = p_bytes; + int ofs = 0; + do { + int chunk = MIN(left, 256); + ERR_FAIL_COND_V(getentropy(r_buffer + ofs, chunk), FAILED); + left -= chunk; + ofs += chunk; + } while (left > 0); +// Define this yourself if you don't want to fall back to /dev/urandom. +#elif !defined(NO_URANDOM) + int r = open("/dev/urandom", O_RDONLY); + ERR_FAIL_COND_V(r < 0, FAILED); + int left = p_bytes; + do { + ssize_t ret = read(r, r_buffer, p_bytes); + ERR_FAIL_COND_V(ret <= 0, FAILED); + left -= ret; + } while (left > 0); +#else + return ERR_UNAVAILABLE; +#endif + return OK; +} + String OS_Unix::get_name() const { return "Unix"; } +String OS_Unix::get_distribution_name() const { + return ""; +} + +String OS_Unix::get_version() const { + return ""; +} + double OS_Unix::get_unix_time() const { struct timeval tv_now; gettimeofday(&tv_now, nullptr); return (double)tv_now.tv_sec + double(tv_now.tv_usec) / 1000000; -}; +} -OS::Date OS_Unix::get_date(bool utc) const { +OS::DateTime OS_Unix::get_datetime(bool p_utc) const { time_t t = time(nullptr); struct tm lt; - if (utc) { + if (p_utc) { gmtime_r(&t, <); } else { localtime_r(&t, <); } - Date ret; + DateTime ret; ret.year = 1900 + lt.tm_year; // Index starting at 1 to match OS_Unix::get_date // and Windows SYSTEMTIME and tm_mon follows the typical structure @@ -185,27 +220,14 @@ OS::Date OS_Unix::get_date(bool utc) const { ret.month = (Month)(lt.tm_mon + 1); ret.day = lt.tm_mday; ret.weekday = (Weekday)lt.tm_wday; + ret.hour = lt.tm_hour; + ret.minute = lt.tm_min; + ret.second = lt.tm_sec; ret.dst = lt.tm_isdst; return ret; } -OS::Time OS_Unix::get_time(bool utc) const { - time_t t = time(nullptr); - struct tm lt; - if (utc) { - gmtime_r(&t, <); - } else { - localtime_r(&t, <); - } - Time ret; - ret.hour = lt.tm_hour; - ret.min = lt.tm_min; - ret.sec = lt.tm_sec; - get_time_zone_info(); - return ret; -} - OS::TimeZoneInfo OS_Unix::get_time_zone_info() const { time_t t = time(nullptr); struct tm lt; @@ -235,8 +257,11 @@ OS::TimeZoneInfo OS_Unix::get_time_zone_info() const { } void OS_Unix::delay_usec(uint32_t p_usec) const { - struct timespec rem = { static_cast<time_t>(p_usec / 1000000), (static_cast<long>(p_usec) % 1000000) * 1000 }; - while (nanosleep(&rem, &rem) == EINTR) { + struct timespec requested = { static_cast<time_t>(p_usec / 1000000), (static_cast<long>(p_usec) % 1000000) * 1000 }; + struct timespec remaining; + while (nanosleep(&requested, &remaining) == -1 && errno == EINTR) { + requested.tv_sec = remaining.tv_sec; + requested.tv_nsec = remaining.tv_nsec; } } @@ -255,45 +280,45 @@ uint64_t OS_Unix::get_ticks_usec() const { return longtime; } -Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex) { +Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) { #ifdef __EMSCRIPTEN__ // Don't compile this code at all to avoid undefined references. - // Actual virtual call goes to OS_JavaScript. + // Actual virtual call goes to OS_Web. ERR_FAIL_V(ERR_BUG); #else - if (p_blocking && r_pipe) { - String argss; - argss = "\"" + p_path + "\""; - + if (r_pipe) { + String command = "\"" + p_path + "\""; for (int i = 0; i < p_arguments.size(); i++) { - argss += String(" \"") + p_arguments[i] + "\""; + command += String(" \"") + p_arguments[i] + "\""; } - if (read_stderr) { - argss += " 2>&1"; // Read stderr too + command += " 2>&1"; // Include stderr } else { - argss += " 2>/dev/null"; //silence stderr + command += " 2>/dev/null"; // Silence stderr } - FILE *f = popen(argss.utf8().get_data(), "r"); - - ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot pipe stream from process running with following arguments '" + argss + "'."); + FILE *f = popen(command.utf8().get_data(), "r"); + ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot create pipe from command: " + command); char buf[65535]; - while (fgets(buf, 65535, f)) { if (p_pipe_mutex) { p_pipe_mutex->lock(); } - (*r_pipe) += String::utf8(buf); + String pipe_out; + if (pipe_out.parse_utf8(buf) == OK) { + (*r_pipe) += pipe_out; + } else { + (*r_pipe) += String(buf); // If not valid UTF-8 try decode as Latin-1 + } if (p_pipe_mutex) { p_pipe_mutex->unlock(); } } int rv = pclose(f); + if (r_exitcode) { *r_exitcode = WEXITSTATUS(rv); } - return OK; } @@ -301,14 +326,7 @@ Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, bo ERR_FAIL_COND_V(pid < 0, ERR_CANT_FORK); if (pid == 0) { - // is child - - if (!p_blocking) { - // For non blocking calls, create a new session-ID so parent won't wait for it. - // This ensures the process won't go zombie at end. - setsid(); - } - + // The child process Vector<CharString> cs; cs.push_back(p_path.utf8()); for (int i = 0; i < p_arguments.size(); i++) { @@ -322,24 +340,56 @@ Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, bo args.push_back(0); execvp(p_path.utf8().get_data(), &args[0]); - // still alive? something failed.. - fprintf(stderr, "**ERROR** OS_Unix::execute - Could not create child process while executing: %s\n", p_path.utf8().get_data()); + // The execvp() function only returns if an error occurs. + ERR_PRINT("Could not create child process: " + p_path); raise(SIGKILL); } - if (p_blocking) { - int status; - waitpid(pid, &status, 0); - if (r_exitcode) { - *r_exitcode = WEXITSTATUS(status); + int status; + waitpid(pid, &status, 0); + if (r_exitcode) { + *r_exitcode = WIFEXITED(status) ? WEXITSTATUS(status) : status; + } + return OK; +#endif +} + +Error OS_Unix::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id, bool p_open_console) { +#ifdef __EMSCRIPTEN__ + // Don't compile this code at all to avoid undefined references. + // Actual virtual call goes to OS_Web. + ERR_FAIL_V(ERR_BUG); +#else + pid_t pid = fork(); + ERR_FAIL_COND_V(pid < 0, ERR_CANT_FORK); + + if (pid == 0) { + // The new process + // Create a new session-ID so parent won't wait for it. + // This ensures the process won't go zombie at the end. + setsid(); + + Vector<CharString> cs; + cs.push_back(p_path.utf8()); + for (int i = 0; i < p_arguments.size(); i++) { + cs.push_back(p_arguments[i].utf8()); } - } else { - if (r_child_id) { - *r_child_id = pid; + Vector<char *> args; + for (int i = 0; i < cs.size(); i++) { + args.push_back((char *)cs[i].get_data()); } + args.push_back(0); + + execvp(p_path.utf8().get_data(), &args[0]); + // The execvp() function only returns if an error occurs. + ERR_PRINT("Could not create child process: " + p_path); + raise(SIGKILL); } + if (r_child_id) { + *r_child_id = pid; + } return OK; #endif } @@ -356,7 +406,16 @@ Error OS_Unix::kill(const ProcessID &p_pid) { int OS_Unix::get_process_id() const { return getpid(); -}; +} + +bool OS_Unix::is_process_running(const ProcessID &p_pid) const { + int status = 0; + if (waitpid(p_pid, &status, WNOHANG) != 0) { + return false; + } + + return true; +} bool OS_Unix::has_environment(const String &p_var) const { return getenv(p_var.utf8().get_data()) != nullptr; @@ -375,27 +434,32 @@ String OS_Unix::get_locale() const { return locale; } -Error OS_Unix::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) { +Error OS_Unix::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) { String path = p_path; - if (FileAccess::exists(path) && path.is_rel_path()) { + if (FileAccess::exists(path) && path.is_relative_path()) { // dlopen expects a slash, in this case a leading ./ for it to be interpreted as a relative path, // otherwise it will end up searching various system directories for the lib instead and finally failing. path = "./" + path; } if (!FileAccess::exists(path)) { - //this code exists so gdnative can load .so files from within the executable path - path = get_executable_path().get_base_dir().plus_file(p_path.get_file()); + // This code exists so GDExtension can load .so files from within the executable path. + path = get_executable_path().get_base_dir().path_join(p_path.get_file()); } if (!FileAccess::exists(path)) { - //this code exists so gdnative can load .so files from a standard unix location - path = get_executable_path().get_base_dir().plus_file("../lib").plus_file(p_path.get_file()); + // This code exists so GDExtension can load .so files from a standard unix location. + path = get_executable_path().get_base_dir().path_join("../lib").path_join(p_path.get_file()); } p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW); ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + p_path + ". Error: " + dlerror()); + + if (r_resolved_path != nullptr) { + *r_resolved_path = path; + } + return OK; } @@ -440,26 +504,22 @@ bool OS_Unix::set_environment(const String &p_var, const String &p_value) const return setenv(p_var.utf8().get_data(), p_value.utf8().get_data(), /* overwrite: */ true) == 0; } -int OS_Unix::get_processor_count() const { - return sysconf(_SC_NPROCESSORS_CONF); -} - String OS_Unix::get_user_data_dir() const { - String appname = get_safe_dir_name(ProjectSettings::get_singleton()->get("application/config/name")); - if (appname != "") { - bool use_custom_dir = ProjectSettings::get_singleton()->get("application/config/use_custom_user_dir"); + 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(ProjectSettings::get_singleton()->get("application/config/custom_user_dir_name"), true); - if (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().plus_file(custom_dir); + return get_data_path().path_join(custom_dir); } else { - return get_data_path().plus_file(get_godot_dir_name()).plus_file("app_userdata").plus_file(appname); + return get_data_path().path_join(get_godot_dir_name()).path_join("app_userdata").path_join(appname); } } - return ProjectSettings::get_singleton()->get_resource_path(); + return get_data_path().path_join(get_godot_dir_name()).path_join("app_userdata").path_join("[unnamed project]"); } String OS_Unix::get_executable_path() const { @@ -472,7 +532,7 @@ String OS_Unix::get_executable_path() const { if (len > 0) { b.parse_utf8(buf, len); } - if (b == "") { + if (b.is_empty()) { WARN_PRINT("Couldn't get executable path from /proc/self/exe, using argv[0]"); return OS::get_executable_path(); } @@ -501,8 +561,9 @@ String OS_Unix::get_executable_path() const { char *resolved_path = new char[buff_size + 1]; - if (_NSGetExecutablePath(resolved_path, &buff_size) == 1) + if (_NSGetExecutablePath(resolved_path, &buff_size) == 1) { WARN_PRINT("MAXPATHLEN is too small"); + } String path(resolved_path); delete[] resolved_path; @@ -514,7 +575,7 @@ String OS_Unix::get_executable_path() const { #endif } -void UnixTerminalLogger::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type) { +void UnixTerminalLogger::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify, ErrorType p_type) { if (!should_log(true)) { return; } diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h index 2982e0c55c..ce06a52a95 100644 --- a/drivers/unix/os_unix.h +++ b/drivers/unix/os_unix.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -43,69 +43,61 @@ protected: virtual void initialize_core(); virtual int unix_initialize_audio(int p_audio_driver); - //virtual Error initialize(int p_video_driver,int p_audio_driver); - virtual void finalize_core(); + virtual void finalize_core() override; String stdin_buf; public: OS_Unix(); - virtual void alert(const String &p_alert, const String &p_title = "ALERT!"); - virtual String get_stdin_string(bool p_block); + virtual Vector<String> get_video_adapter_driver_info() const override; - //virtual void set_mouse_show(bool p_show); - //virtual void set_mouse_grab(bool p_grab); - //virtual bool is_mouse_grab_enabled() const = 0; - //virtual void get_mouse_position(int &x, int &y) const; - //virtual void set_window_title(const String& p_title); + virtual String get_stdin_string(bool p_block) override; - //virtual void set_video_mode(const VideoMode& p_video_mode); - //virtual VideoMode get_video_mode() const; - //virtual void get_fullscreen_mode_list(List<VideoMode> *p_list) const; + virtual Error get_entropy(uint8_t *r_buffer, int p_bytes) override; - virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false); - virtual Error close_dynamic_library(void *p_library_handle); - virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false); + virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false, String *r_resolved_path = nullptr) override; + virtual Error close_dynamic_library(void *p_library_handle) override; + virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false) override; - virtual Error set_cwd(const String &p_cwd); + virtual Error set_cwd(const String &p_cwd) override; - virtual String get_name() const; + virtual String get_name() const override; + virtual String get_distribution_name() const override; + virtual String get_version() const override; - virtual Date get_date(bool utc) const; - virtual Time get_time(bool utc) const; - virtual TimeZoneInfo get_time_zone_info() const; + virtual DateTime get_datetime(bool p_utc) const override; + virtual TimeZoneInfo get_time_zone_info() const override; - virtual double get_unix_time() const; + virtual double get_unix_time() const override; - virtual void delay_usec(uint32_t p_usec) const; - virtual uint64_t get_ticks_usec() const; + virtual void delay_usec(uint32_t p_usec) const override; + virtual uint64_t get_ticks_usec() const override; - virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr); - virtual Error kill(const ProcessID &p_pid); - virtual int get_process_id() const; + 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 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; + virtual bool is_process_running(const ProcessID &p_pid) const override; - virtual bool has_environment(const String &p_var) const; - virtual String get_environment(const String &p_var) const; - virtual bool set_environment(const String &p_var, const String &p_value) const; - virtual String get_locale() const; + virtual bool has_environment(const String &p_var) const override; + virtual String get_environment(const String &p_var) const override; + virtual bool set_environment(const String &p_var, const String &p_value) const override; + virtual String get_locale() const override; - virtual int get_processor_count() const; + virtual void initialize_debugging() override; - virtual void debug_break(); - virtual void initialize_debugging(); - - virtual String get_executable_path() const; - virtual String get_user_data_dir() const; + virtual String get_executable_path() const override; + virtual String get_user_data_dir() const override; }; class UnixTerminalLogger : public StdLogger { public: - virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type = ERR_ERROR); + virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify = false, ErrorType p_type = ERR_ERROR) override; virtual ~UnixTerminalLogger(); }; -#endif +#endif // UNIX_ENABLED -#endif +#endif // OS_UNIX_H diff --git a/drivers/unix/rw_lock_posix.cpp b/drivers/unix/rw_lock_posix.cpp deleted file mode 100644 index 50b74e84f7..0000000000 --- a/drivers/unix/rw_lock_posix.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/*************************************************************************/ -/* rw_lock_posix.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#if defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED) - -#include "rw_lock_posix.h" - -#include "core/error_macros.h" -#include "core/os/memory.h" -#include <stdio.h> - -void RWLockPosix::read_lock() { - int err = pthread_rwlock_rdlock(&rwlock); - if (err != 0) { - perror("Acquiring lock failed"); - } - ERR_FAIL_COND(err != 0); -} - -void RWLockPosix::read_unlock() { - pthread_rwlock_unlock(&rwlock); -} - -Error RWLockPosix::read_try_lock() { - if (pthread_rwlock_tryrdlock(&rwlock) != 0) { - return ERR_BUSY; - } else { - return OK; - } -} - -void RWLockPosix::write_lock() { - int err = pthread_rwlock_wrlock(&rwlock); - ERR_FAIL_COND(err != 0); -} - -void RWLockPosix::write_unlock() { - pthread_rwlock_unlock(&rwlock); -} - -Error RWLockPosix::write_try_lock() { - if (pthread_rwlock_trywrlock(&rwlock) != 0) { - return ERR_BUSY; - } else { - return OK; - } -} - -RWLock *RWLockPosix::create_func_posix() { - return memnew(RWLockPosix); -} - -void RWLockPosix::make_default() { - create_func = create_func_posix; -} - -RWLockPosix::RWLockPosix() { - //rwlock=PTHREAD_RWLOCK_INITIALIZER; fails on OSX - pthread_rwlock_init(&rwlock, nullptr); -} - -RWLockPosix::~RWLockPosix() { - pthread_rwlock_destroy(&rwlock); -} - -#endif diff --git a/drivers/unix/rw_lock_posix.h b/drivers/unix/rw_lock_posix.h deleted file mode 100644 index 056fcaea1c..0000000000 --- a/drivers/unix/rw_lock_posix.h +++ /dev/null @@ -1,62 +0,0 @@ -/*************************************************************************/ -/* rw_lock_posix.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef RWLOCKPOSIX_H -#define RWLOCKPOSIX_H - -#if defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED) - -#include "core/os/rw_lock.h" -#include <pthread.h> - -class RWLockPosix : public RWLock { - pthread_rwlock_t rwlock; - - static RWLock *create_func_posix(); - -public: - virtual void read_lock(); - virtual void read_unlock(); - virtual Error read_try_lock(); - - virtual void write_lock(); - virtual void write_unlock(); - virtual Error write_try_lock(); - - static void make_default(); - - RWLockPosix(); - - ~RWLockPosix(); -}; - -#endif - -#endif // RWLOCKPOSIX_H diff --git a/drivers/unix/syslog_logger.cpp b/drivers/unix/syslog_logger.cpp index a4c7070f0e..6189d645c6 100644 --- a/drivers/unix/syslog_logger.cpp +++ b/drivers/unix/syslog_logger.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,7 +31,9 @@ #ifdef UNIX_ENABLED #include "syslog_logger.h" -#include "core/print_string.h" + +#include "core/string/print_string.h" + #include <syslog.h> void SyslogLogger::logv(const char *p_format, va_list p_list, bool p_err) { diff --git a/drivers/unix/syslog_logger.h b/drivers/unix/syslog_logger.h index 52da12481f..cc6617eb25 100644 --- a/drivers/unix/syslog_logger.h +++ b/drivers/unix/syslog_logger.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -43,6 +43,6 @@ public: virtual ~SyslogLogger(); }; -#endif +#endif // UNIX_ENABLED -#endif +#endif // SYSLOG_LOGGER_H diff --git a/drivers/unix/thread_posix.cpp b/drivers/unix/thread_posix.cpp index 285088342b..5154feb478 100644 --- a/drivers/unix/thread_posix.cpp +++ b/drivers/unix/thread_posix.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,88 +28,18 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "thread_posix.h" +#if defined(UNIX_ENABLED) -#if (defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED)) && !defined(NO_THREADS) +#include "thread_posix.h" -#include "core/os/memory.h" -#include "core/safe_refcount.h" -#include "core/script_language.h" +#include "core/os/thread.h" +#include "core/string/ustring.h" #ifdef PTHREAD_BSD_SET_NAME #include <pthread_np.h> #endif -static void _thread_id_key_destr_callback(void *p_value) { - memdelete(static_cast<Thread::ID *>(p_value)); -} - -static pthread_key_t _create_thread_id_key() { - pthread_key_t key; - pthread_key_create(&key, &_thread_id_key_destr_callback); - return key; -} - -pthread_key_t ThreadPosix::thread_id_key = _create_thread_id_key(); -Thread::ID ThreadPosix::next_thread_id = 0; - -Thread::ID ThreadPosix::get_id() const { - return id; -} - -Thread *ThreadPosix::create_thread_posix() { - return memnew(ThreadPosix); -} - -void *ThreadPosix::thread_callback(void *userdata) { - ThreadPosix *t = reinterpret_cast<ThreadPosix *>(userdata); - t->id = atomic_increment(&next_thread_id); - pthread_setspecific(thread_id_key, (void *)memnew(ID(t->id))); - - ScriptServer::thread_enter(); //scripts may need to attach a stack - - t->callback(t->user); - - ScriptServer::thread_exit(); - - return nullptr; -} - -Thread *ThreadPosix::create_func_posix(ThreadCreateCallback p_callback, void *p_user, const Settings &) { - ThreadPosix *tr = memnew(ThreadPosix); - tr->callback = p_callback; - tr->user = p_user; - pthread_attr_init(&tr->pthread_attr); - pthread_attr_setdetachstate(&tr->pthread_attr, PTHREAD_CREATE_JOINABLE); - pthread_attr_setstacksize(&tr->pthread_attr, 256 * 1024); - - pthread_create(&tr->pthread, &tr->pthread_attr, thread_callback, tr); - - return tr; -} - -Thread::ID ThreadPosix::get_thread_id_func_posix() { - void *value = pthread_getspecific(thread_id_key); - - if (value) { - return *static_cast<ID *>(value); - } - - ID new_id = atomic_increment(&next_thread_id); - pthread_setspecific(thread_id_key, (void *)memnew(ID(new_id))); - return new_id; -} - -void ThreadPosix::wait_to_finish_func_posix(Thread *p_thread) { - ThreadPosix *tp = static_cast<ThreadPosix *>(p_thread); - ERR_FAIL_COND(!tp); - ERR_FAIL_COND(tp->pthread == 0); - - pthread_join(tp->pthread, nullptr); - tp->pthread = 0; -} - -Error ThreadPosix::set_name_func_posix(const String &p_name) { +static Error set_name(const String &p_name) { #ifdef PTHREAD_NO_RENAME return ERR_UNAVAILABLE; @@ -137,20 +67,10 @@ Error ThreadPosix::set_name_func_posix(const String &p_name) { return err == 0 ? OK : ERR_INVALID_PARAMETER; #endif // PTHREAD_NO_RENAME -}; - -void ThreadPosix::make_default() { - create_func = create_func_posix; - get_thread_id_func = get_thread_id_func_posix; - wait_to_finish_func = wait_to_finish_func_posix; - set_name_func = set_name_func_posix; -} - -ThreadPosix::ThreadPosix() { - pthread = 0; } -ThreadPosix::~ThreadPosix() { +void init_thread_posix() { + Thread::_set_platform_functions({ .set_name = set_name }); } -#endif +#endif // UNIX_ENABLED diff --git a/drivers/unix/thread_posix.h b/drivers/unix/thread_posix.h index 6607dbd111..87e42b3870 100644 --- a/drivers/unix/thread_posix.h +++ b/drivers/unix/thread_posix.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,42 +31,6 @@ #ifndef THREAD_POSIX_H #define THREAD_POSIX_H -#if (defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED)) && !defined(NO_THREADS) +void init_thread_posix(); -#include "core/os/thread.h" -#include <pthread.h> -#include <sys/types.h> - -class ThreadPosix : public Thread { - static pthread_key_t thread_id_key; - static ID next_thread_id; - - pthread_t pthread; - pthread_attr_t pthread_attr; - ThreadCreateCallback callback; - void *user; - ID id; - - static Thread *create_thread_posix(); - - static void *thread_callback(void *userdata); - - static Thread *create_func_posix(ThreadCreateCallback p_callback, void *, const Settings &); - static ID get_thread_id_func_posix(); - static void wait_to_finish_func_posix(Thread *p_thread); - - static Error set_name_func_posix(const String &p_name); - - ThreadPosix(); - -public: - virtual ID get_id() const; - - static void make_default(); - - ~ThreadPosix(); -}; - -#endif - -#endif +#endif // THREAD_POSIX_H |