From a8d3cd9b157f78543d6adaddcdb5ea211b7f7263 Mon Sep 17 00:00:00 2001 From: Christian Helmuth Date: Fri, 6 Nov 2020 11:31:28 +0100 Subject: [PATCH] libc: open socket files early on socket creation This prevents later file-descriptor shortage when opening files on demand, which can't be reflected to the application in a sane manner. The real fix is to open socket files not on libc level but on VFS level only effectively consume one libc file descriptor for one socket. --- repos/dde_linux/src/lib/vfs/lxip/vfs.cc | 13 +-- .../libports/src/lib/libc/socket_fs_plugin.cc | 103 ++++++++++-------- 2 files changed, 62 insertions(+), 54 deletions(-) diff --git a/repos/dde_linux/src/lib/vfs/lxip/vfs.cc b/repos/dde_linux/src/lib/vfs/lxip/vfs.cc index 096404d7a8..e391899976 100644 --- a/repos/dde_linux/src/lib/vfs/lxip/vfs.cc +++ b/repos/dde_linux/src/lib/vfs/lxip/vfs.cc @@ -1047,10 +1047,12 @@ class Vfs::Lxip_socket_dir final : public Lxip::Socket_dir for (Vfs::File * &file : _files) file = nullptr; + _files[ACCEPT_NODE] = &_accept_file; _files[BIND_NODE] = &_bind_file; _files[CONNECT_NODE] = &_connect_file; _files[DATA_NODE] = &_data_file; _files[PEEK_NODE] = &_peek_file; + _files[LISTEN_NODE] = &_listen_file; _files[LOCAL_NODE] = &_local_file; _files[REMOTE_NODE] = &_remote_file; } @@ -1110,23 +1112,16 @@ class Vfs::Lxip_socket_dir final : public Lxip::Socket_dir return Vfs::Directory_service::OPEN_ERR_UNACCESSIBLE; } - void bind(bool v) override - { - _files[LISTEN_NODE] = v ? &_listen_file : nullptr; - } + void bind(bool v) override { } long bind() override { return _bind_file.port(); } bool lookup_port(long port) override { return _parent.lookup_port(port); } - void connect(bool v) override - { - _files[REMOTE_NODE] = v ? &_remote_file : nullptr; - } + void connect(bool v) override { } void listen(bool v) override { - _files[ACCEPT_NODE] = v ? &_accept_file : nullptr; _files[ACCEPT_SOCKET_NODE] = v ? &_accept_socket_file : nullptr; } diff --git a/repos/libports/src/lib/libc/socket_fs_plugin.cc b/repos/libports/src/lib/libc/socket_fs_plugin.cc index 3bde44ff80..5b8c46fcb8 100644 --- a/repos/libports/src/lib/libc/socket_fs_plugin.cc +++ b/repos/libports/src/lib/libc/socket_fs_plugin.cc @@ -103,9 +103,24 @@ using namespace Libc::Socket_fs; struct Libc::Socket_fs::Context : Plugin_context { + public: + + enum Proto { TCP, UDP }; + + enum State { UNCONNECTED, ACCEPT_ONLY, CONNECTING, CONNECTED, CONNECT_ABORTED }; + + /* TODO remove */ + struct Inaccessible { }; /* exception */ + private: + /* + * This is the file descriptor representing the socket and must be held + * open until the socket is closed. The file content is the location of + * the socket in the socket FS. + */ int const _handle_fd; + int _fd_flags { 0 }; Absolute_path _read_socket_path() { @@ -119,22 +134,10 @@ struct Libc::Socket_fs::Context : Plugin_context return path; } - public: - - enum Proto { TCP, UDP }; - - enum State { UNCONNECTED, ACCEPT_ONLY, CONNECTING, CONNECTED, CONNECT_ABORTED }; - - struct Inaccessible { }; /* exception */ - - Absolute_path const path { + Absolute_path const _path { _read_socket_path().base(), config_socket() }; - private: - - enum Fd : unsigned { - DATA, PEEK, CONNECT, BIND, LISTEN, ACCEPT, LOCAL, REMOTE, MAX - }; + enum Fd { DATA, PEEK, CONNECT, BIND, LISTEN, ACCEPT, LOCAL, REMOTE, MAX }; struct { @@ -148,7 +151,6 @@ struct Libc::Socket_fs::Context : Plugin_context { "local", -1, nullptr }, { "remote", -1, nullptr } }; - int _fd_flags = 0; Proto const _proto; @@ -161,21 +163,18 @@ struct Libc::Socket_fs::Context : Plugin_context if (_fd[i].num != -1) fn(_fd[i].num); } - int _fd_for_type(Fd type, int flags) + void _init_fd(Fd type, int flags) { - /* open file on demand */ - if (_fd[type].num == -1) { - Absolute_path file(_fd[type].name, path.base()); - int const fd = open(file.base(), flags|_fd_flags); - if (fd == -1) { - error(__func__, ": ", _fd[type].name, " file not accessible at ", file); - throw Inaccessible(); - } - _fd[type].num = fd; - _fd[type].file = file_descriptor_allocator()->find_by_libc_fd(fd); + Absolute_path file(_fd[type].name, _path.base()); + int const fd = open(file.base(), flags|_fd_flags); + if (fd == -1) { + error(__func__, ": ", _fd[type].name, + " file not accessible at ", file, + " errno=", errno); + throw New_socket_failed(); } - - return _fd[type].num; + _fd[type].num = fd; + _fd[type].file = file_descriptor_allocator()->find_by_libc_fd(fd); } bool _fd_read_ready(Fd type) @@ -189,7 +188,17 @@ struct Libc::Socket_fs::Context : Plugin_context public: Context(Proto proto, int handle_fd) - : _handle_fd(handle_fd), _proto(proto) { } + : _handle_fd(handle_fd), _proto(proto) + { + _init_fd(Fd::DATA, O_RDWR); + _init_fd(Fd::PEEK, O_RDONLY); + _init_fd(Fd::CONNECT, O_RDWR); + _init_fd(Fd::BIND, O_WRONLY); + _init_fd(Fd::LISTEN, O_WRONLY); + _init_fd(Fd::ACCEPT, O_RDONLY); + _init_fd(Fd::LOCAL, O_RDWR); + _init_fd(Fd::REMOTE, O_RDWR); + } ~Context() { @@ -197,6 +206,8 @@ struct Libc::Socket_fs::Context : Plugin_context ::close(_handle_fd); } + Absolute_path path() const { return _path; } + Proto proto() const { return _proto; } int fd_flags() const { return _fd_flags; } @@ -206,21 +217,21 @@ struct Libc::Socket_fs::Context : Plugin_context _fd_apply([flags] (int fd) { fcntl(fd, F_SETFL, flags); }); } - int data_fd() { return _fd_for_type(Fd::DATA, O_RDWR); } - int peek_fd() { return _fd_for_type(Fd::PEEK, O_RDONLY); } - int connect_fd() { return _fd_for_type(Fd::CONNECT, O_RDWR); } - int bind_fd() { return _fd_for_type(Fd::BIND, O_WRONLY); } - int listen_fd() { return _fd_for_type(Fd::LISTEN, O_WRONLY); } - int accept_fd() { return _fd_for_type(Fd::ACCEPT, O_RDONLY); } - int local_fd() { return _fd_for_type(Fd::LOCAL, O_RDWR); } - int remote_fd() { return _fd_for_type(Fd::REMOTE, O_RDWR); } + int data_fd() { return _fd[Fd::DATA].num; } + int peek_fd() { return _fd[Fd::PEEK].num; } + int connect_fd() { return _fd[Fd::CONNECT].num; } + int bind_fd() { return _fd[Fd::BIND].num; } + int listen_fd() { return _fd[Fd::LISTEN].num; } + int accept_fd() { return _fd[Fd::ACCEPT].num; } + int local_fd() { return _fd[Fd::LOCAL].num; } + int remote_fd() { return _fd[Fd::REMOTE].num; } /* request the appropriate fd to ensure the file is open */ - bool connect_read_ready() { connect_fd(); return _fd_read_ready(Fd::CONNECT); } - bool data_read_ready() { data_fd(); return _fd_read_ready(Fd::DATA); } - bool accept_read_ready() { accept_fd(); return _fd_read_ready(Fd::ACCEPT); } - bool local_read_ready() { local_fd(); return _fd_read_ready(Fd::LOCAL); } - bool remote_read_ready() { remote_fd(); return _fd_read_ready(Fd::REMOTE); } + bool connect_read_ready() { return _fd_read_ready(Fd::CONNECT); } + bool data_read_ready() { return _fd_read_ready(Fd::DATA); } + bool accept_read_ready() { return _fd_read_ready(Fd::ACCEPT); } + bool local_read_ready() { return _fd_read_ready(Fd::LOCAL); } + bool remote_read_ready() { return _fd_read_ready(Fd::REMOTE); } void state(State state) { _state = state; } State state() const { return _state; } @@ -551,7 +562,7 @@ extern "C" int socket_fs_accept(int libc_fd, sockaddr *addr, socklen_t *addrlen) return Errno(EINVAL); } - Socket_fs::Absolute_path path = listen_context->path; + Socket_fs::Absolute_path path { listen_context->path() }; path.append("/accept_socket"); int handle_fd = ::open(path.base(), O_RDONLY); @@ -567,7 +578,7 @@ extern "C" int socket_fs_accept(int libc_fd, sockaddr *addr, socklen_t *addrlen) Socket_fs::Context(listen_context->proto(), handle_fd); } catch (New_socket_failed) { close(handle_fd); - return Errno(EACCES); + return Errno(ENFILE); } File_descriptor *accept_fd = @@ -1035,7 +1046,7 @@ extern "C" int socket_fs_socket(int domain, int type, int protocol) Libc::Allocator alloc { }; context = new (alloc) Socket_fs::Context(proto, handle_fd); - } catch (New_socket_failed) { return Errno(EACCES); } + } catch (New_socket_failed) { return Errno(ENFILE); } File_descriptor *fd = file_descriptor_allocator()->alloc(&plugin(), context); if (!fd) { @@ -1292,10 +1303,12 @@ int Socket_fs::Plugin::ioctl(File_descriptor *, unsigned long request, char*) " (this message will not be shown again)"); print_fionread_error_message = false; } + errno = EINVAL; return -1; } error(__func__, " request ", request, " not supported on sockets"); + errno = ENOTTY; return -1; }