def test_is_socket_unix(): with closing_socketpair(socket.AF_UNIX) as pair: for sock in pair: for arg in (sock, sock.fileno()): assert is_socket_unix(arg) assert not is_socket_unix(arg, path="/no/such/path") assert is_socket_unix(arg, socket.SOCK_STREAM) assert not is_socket_unix(arg, socket.SOCK_DGRAM)
def _get_systemd_socket(self, address): fds = sd.listen_fds() if not fds: return address elif len(fds) > 1: raise ValueError('Too many listening sockets', fds) if isinstance(address, tuple): port = address[1] # systemd uses IPv6 if not sd.is_socket_inet(fds[0], family=socket.AF_INET6, type=socket.SOCK_STREAM, listening=True, port=port): raise ValueError("FD {} is not TCP IPv6 socket on port {}", fds[0], port) logger.info('Using systemd socket activation on port %i', port) sock = socket.fromfd(fds[0], socket.AF_INET6, socket.SOCK_STREAM) else: if not sd.is_socket_unix( fds[0], socket.SOCK_STREAM, listening=True, path=address): raise ValueError("FD {} is not Unix stream socket on path {}", fds[0], address) logger.info('Using systemd socket activation on path %s', address) sock = socket.fromfd(fds[0], socket.AF_UNIX, socket.SOCK_STREAM) if sys.version_info[0] < 3: # Python 2.7's socket.fromfd() returns _socket.socket sock = socket.socket(_sock=sock) return sock
def _get_systemd_socket(self, address): fds = sd.listen_fds() if not fds: return address elif len(fds) > 1: raise ValueError('Too many listening sockets', fds) if isinstance(address, tuple): port = address[1] # systemd uses IPv6 if not sd.is_socket_inet(fds[0], family=socket.AF_INET6, type=socket.SOCK_STREAM, listening=True, port=port): raise ValueError("FD {} is not TCP IPv6 socket on port {}", fds[0], port) logger.info('Using systemd socket activation on port %i', port) sock = socket.fromfd(fds[0], socket.AF_INET6, socket.SOCK_STREAM) else: if not sd.is_socket_unix(fds[0], socket.SOCK_STREAM, listening=True, path=address): raise ValueError("FD {} is not Unix stream socket on path {}", fds[0], address) logger.info('Using systemd socket activation on path %s', address) sock = socket.fromfd(fds[0], socket.AF_UNIX, socket.SOCK_STREAM) if sys.version_info[0] < 3: # Python 2.7's socket.fromfd() returns _socket.socket sock = socket.socket(_sock=sock) return sock
def sock_from_fd(fd): if is_socket(fd): if is_socket_unix(fd): return socket.socket(family=socket.AF_UNIX, type=socket.SOCK_STREAM, fileno=fd) for fam in [socket.AF_INET6, socket.AF_INET]: for t in [socket.SOCK_STREAM]: if is_socket(fd, family=fam, type=t): return socket.socket(family=fam, type=t, fileno=fd) return socket.socket(fileno=fd) return None
def main(): parser = ArgumentParser( description="Listens for commands as output by `hades-dhcp-script`.", epilog=f"""\ This server listens on a socket for commands communicating lease events. For detailed information about the functionality see `hades-dhcp-script --help`. It is the server component for what could have been a single python program, however because of performance reasons, it was necessary to circumvent the need for a complete python interpreter startup every time such a notification happens.\ """, parents=[common_parser], ) parser.add_argument( '--socket', nargs='?', default=constants.AUTH_DHCP_SCRIPT_SOCKET, help= f"Socket to listen on. Default: {constants.AUTH_DHCP_SCRIPT_SOCKET}") args = parser.parse_args() SCRIPT_SOCKET = args.socket setup_cli_logging(parser.prog, args) try: config = load_config(args.config) except ConfigError as e: print_config_error(e) return os.EX_CONFIG fds = listen_fds() if len(fds) == 0: logger.info( "Opening UNIX socket at %s.", SCRIPT_SOCKET, ) sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM, 0) try: os.unlink(SCRIPT_SOCKET) except FileNotFoundError: pass sock.bind(SCRIPT_SOCKET) sock.listen(Server.request_queue_size) elif len(fds) == 1: logger.info("Using systemd activation socket") sock = fds[0] if not is_socket_unix(sock, socket.SOCK_STREAM): logger.critical( "Passed socket is not an AF_UNIX SOCK_STREAM socket") return os.EX_USAGE else: logger.critical( "More than one (%d) socket passed via socket activation", len(fds), ) return os.EX_USAGE engine = db.create_engine( config, pool_size=1, max_overflow=2, pool_pre_ping=True, pool_reset_on_return='rollback', ) try: engine.connect() except DBAPIError as e: logger.critical("Could not connect to database", exc_info=e) return os.EX_TEMPFAIL server = Server(sock, engine) server.serve_forever() return os.EX_OK