mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-08 03:45:24 +00:00
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.
This commit is contained in:
parent
5dfca79bcc
commit
a8d3cd9b15
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user