Skip to content

Commit

Permalink
Fix ip transport not reconnecting right away
Browse files Browse the repository at this point in the history
There were two problems that prevented the IP transport
from reconnecting

1. When the connection was lost, _start_connector would
   not try to reconnect because self.transport and
   self.protocol were still set which meant the connection
   was not full torn down and it thought it was still
   connected. This is fixed by clearing transport and
   protocol before calling _start_connector.

2. If a request was inflight the connection would get
   re-established and than the concurrency lock would
   prevent the pair-verify from happening. This is fixed
   by resolving all the futures that are waiting when
   the connection is lost.
  • Loading branch information
bdraco committed Aug 11, 2024
1 parent af96747 commit 8e641be
Showing 1 changed file with 20 additions and 8 deletions.
28 changes: 20 additions & 8 deletions aiohomekit/controller/ip/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ def connection_made(self, transport):

def connection_lost(self, exception):
self.connection._connection_lost(exception)
self._cancel_pending_requests()

def _handle_timeout(self, fut: asyncio.Future[Any]) -> None:
"""Handle a timeout."""
Expand Down Expand Up @@ -151,6 +152,9 @@ def eof_received(self):
return False

def close(self):
self._cancel_pending_requests()

def _cancel_pending_requests(self) -> None:
# If the connection is closed then any pending callbacks will never
# fire, so set them to an error state.
while self.result_cbs:
Expand Down Expand Up @@ -557,19 +561,19 @@ def _connection_lost(self, exception: Exception) -> None:
Called by a Protocol instance when eof_received happens.
"""
logger.debug("Connection %r lost.", self)

if not self.closing:
self._start_connector()

if self.closing:
self.closed = True

# Clear the transport and protocol right away
# as otherwise _start_connector will see them and
# think we are still connected.
self.transport = None
self.protocol = None
if self.closing:
self.closed = True
else:
self._start_connector()

async def _connect_once(self) -> None:
"""_connect_once must only ever be called from _reconnect to ensure its done with a lock."""
loop = asyncio.get_event_loop()
loop = asyncio.get_running_loop()

logger.debug("Attempting connection to %s:%s", self.hosts, self.port)

Expand Down Expand Up @@ -597,6 +601,7 @@ async def _connect_once(self) -> None:
raise TimeoutError("Timeout") from last_exception
raise ConnectionError(str(last_exception)) from last_exception

logger.debug("Connected established to %s:%s", self.hosts, self.port)
# set keep-alive on the socket to ensure we detect dropped connections
# since we don't send keep-alive packets ourselves
sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
Expand All @@ -616,7 +621,9 @@ async def _connect_once(self) -> None:
self.host_header = f"Host: [{connected_host}]"
else:
self.host_header = f"Host: {connected_host}"

if self.owner:
logger.debug("Connection made to %s:%s", self.hosts, self.port)
await self.owner.connection_made(False)

async def _reconnect(self) -> None:
Expand Down Expand Up @@ -736,6 +743,11 @@ async def _connect_once(self):
pass

await super()._connect_once()
logger.debug(
"SecureHomeKitConnection established to %s:%s",
self.connected_host,
self.port,
)

state_machine = get_session_keys(self.pairing_data)

Expand Down

0 comments on commit 8e641be

Please sign in to comment.