/* * \brief Linux-specific socket-descriptor registry * \author Norman Feske * \date 2012-07-26 * * We use the names of Unix-domain sockets as keys to uniquely identify * entrypoints. When receiving a socket descriptor as IPC payload, we first * lookup the corresponding entrypoint ID. If we already possess a socket * descriptor pointing to the same entrypoint, we close the received one and * use the already known descriptor instead. */ /* * Copyright (C) 2012-2013 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. */ #ifndef _BASE__IPC__SOCKET_DESCRIPTOR_REGISTRY_H_ #define _BASE__IPC__SOCKET_DESCRIPTOR_REGISTRY_H_ #include namespace Genode { template class Socket_descriptor_registry; typedef Socket_descriptor_registry<100> Ep_socket_descriptor_registry; /** * Return singleton instance of registry for tracking entrypoint sockets */ Ep_socket_descriptor_registry *ep_sd_registry(); } template class Genode::Socket_descriptor_registry { public: class Limit_reached { }; class Aliased_global_id { }; private: struct Entry { int fd; int global_id; /** * Default constructor creates empty entry */ Entry() : fd(-1), global_id(-1) { } Entry(int fd, int global_id) : fd(fd), global_id(global_id) { } bool is_free() const { return fd == -1; } void mark_as_free() { fd = -1; } }; Entry _entries[MAX_FDS]; Genode::Lock mutable _lock; Entry &_find_free_entry() { for (unsigned i = 0; i < MAX_FDS; i++) if (_entries[i].is_free()) return _entries[i]; throw Limit_reached(); } Entry &_find_entry_by_fd(int fd) { for (unsigned i = 0; i < MAX_FDS; i++) if (_entries[i].fd == fd) return _entries[i]; throw Limit_reached(); } /** * Lookup file descriptor that belongs to specified global ID * * \return file descriptor or -1 if lookup failed */ int _lookup_fd_by_global_id(int global_id) const { for (unsigned i = 0; i < MAX_FDS; i++) if (_entries[i].global_id == global_id) return _entries[i].fd; return -1; } public: void disassociate(int sd) { Genode::Lock::Guard guard(_lock); for (unsigned i = 0; i < MAX_FDS; i++) if (_entries[i].fd == sd) { _entries[i].mark_as_free(); return; } } /** * Try to associate socket descriptor with corresponding ID * * \return socket descriptor associated with the ID * \throw Limit_reached * * If the ID was already associated, the return value is the originally * registered socket descriptor. In this case, the caller should drop * the new socket descriptor and use the one returned by this function. */ int try_associate(int sd, int global_id) { /* ignore invalid capabilities */ if (sd == -1) return sd; /* ignore invalid capabilities */ if (sd == -1 || global_id == -1) return sd; Genode::Lock::Guard guard(_lock); int const existing_sd = _lookup_fd_by_global_id(global_id); if (existing_sd < 0) { Entry &entry = _find_free_entry(); entry = Entry(sd, global_id); return sd; } else { return existing_sd; } } }; #endif /* _BASE__IPC__SOCKET_DESCRIPTOR_REGISTRY_H_ */