moonraker: don't allow a unix socket to open while closing

Hold the closed mutex in the "connect()" method.

Signed-off-by:  Eric Callahan <arksine.code@gmail.com>
This commit is contained in:
Eric Callahan 2021-12-12 08:24:04 -05:00
parent 31dd758d52
commit 3f7cc53baa
1 changed files with 39 additions and 36 deletions

View File

@ -707,35 +707,36 @@ class KlippyConnection:
event_loop: EventLoop event_loop: EventLoop
) -> None: ) -> None:
self.writer: Optional[asyncio.StreamWriter] = None self.writer: Optional[asyncio.StreamWriter] = None
self.closed: bool = True self.connection_mutex: asyncio.Lock = asyncio.Lock()
self.close_mutex: asyncio.Lock = asyncio.Lock()
self.on_recd = on_recd self.on_recd = on_recd
self.on_close = on_close self.on_close = on_close
self.event_loop = event_loop self.event_loop = event_loop
self.log_no_access = True self.log_no_access = True
async def connect(self, address: str) -> bool: async def connect(self, address: str) -> bool:
if not os.path.exists(address): if self.is_connected():
return False await self.close()
if not os.access(address, os.R_OK | os.W_OK): async with self.connection_mutex:
if self.log_no_access: if not os.path.exists(address):
user = getpass.getuser() return False
logging.info( if not os.access(address, os.R_OK | os.W_OK):
f"Cannot connect to Klippy, Linux user '{user}' lacks " if self.log_no_access:
f"permission to open Unix Domain Socket: {address}") user = getpass.getuser()
self.log_no_access = False logging.info(
return False f"Cannot connect to Klippy, Linux user '{user}' lacks "
self.log_no_access = True f"permission to open Unix Domain Socket: {address}")
try: self.log_no_access = False
reader, writer = await asyncio.open_unix_connection( return False
address, limit=UNIX_BUFFER_LIMIT) self.log_no_access = True
except Exception: try:
return False reader, writer = await asyncio.open_unix_connection(
logging.info("Klippy Connection Established") address, limit=UNIX_BUFFER_LIMIT)
self.closed = False except Exception:
self.writer = writer return False
self.event_loop.register_callback(self._read_stream, reader) logging.info("Klippy Connection Established")
return True self.writer = writer
self.event_loop.register_callback(self._read_stream, reader)
return True
async def _read_stream(self, reader: asyncio.StreamReader) -> None: async def _read_stream(self, reader: asyncio.StreamReader) -> None:
errors_remaining: int = 10 errors_remaining: int = 10
@ -770,21 +771,23 @@ class KlippyConnection:
await self.close() await self.close()
def is_connected(self) -> bool: def is_connected(self) -> bool:
return not self.closed return self.writer is not None
async def close(self) -> None: async def close(self) -> None:
async with self.close_mutex: if (
if self.writer is not None: self.connection_mutex.locked() or
try: self.writer is None
self.writer.close() ):
await self.writer.wait_closed() return
except Exception: async with self.connection_mutex:
logging.exception("Error closing Klippy Unix Socket") try:
self.writer = None self.writer.close()
if not self.closed: await self.writer.wait_closed()
self.closed = True except Exception:
self.on_close() logging.exception("Error closing Klippy Unix Socket")
self.closing = False self.writer = None
self.on_close()
# Basic WebRequest class, easily converted to dict for json encoding # Basic WebRequest class, easily converted to dict for json encoding
class BaseRequest: class BaseRequest: