Merge remote-tracking branch 'origin/dmw'

- issue #416.
issue260
David Wilson 6 years ago
commit fdcd6810e1

@ -223,6 +223,10 @@ Core Library
was configured. This would lead to connection timeouts due to the hung was configured. This would lead to connection timeouts due to the hung
response. response.
* `#416 <https://github.com/dw/mitogen/issues/416>`_: around 1.4KiB of memory
was leaked on every RPC, due to a list of strong references keeping alive any
handler ever registered for disconnect notification.
* `16ca111e <https://github.com/dw/mitogen/commit/16ca111e>`_: handle OpenSSH * `16ca111e <https://github.com/dw/mitogen/commit/16ca111e>`_: handle OpenSSH
7.5 permission denied prompts when ``~/.ssh/config`` rewrites are present. 7.5 permission denied prompts when ``~/.ssh/config`` rewrites are present.

@ -2087,6 +2087,8 @@ class Router(object):
self._last_handle = itertools.count(1000) self._last_handle = itertools.count(1000)
#: handle -> (persistent?, func(msg)) #: handle -> (persistent?, func(msg))
self._handle_map = {} self._handle_map = {}
#: Context -> set { handle, .. }
self._handles_by_respondent = {}
self.add_handler(self._on_del_route, DEL_ROUTE) self.add_handler(self._on_del_route, DEL_ROUTE)
def __repr__(self): def __repr__(self):
@ -2117,7 +2119,7 @@ class Router(object):
def _on_broker_exit(self): def _on_broker_exit(self):
while self._handle_map: while self._handle_map:
_, (_, func, _) = self._handle_map.popitem() _, (_, func, _, _) = self._handle_map.popitem()
func(Message.dead()) func(Message.dead())
def context_by_id(self, context_id, via_id=None, create=True, name=None): def context_by_id(self, context_id, via_id=None, create=True, name=None):
@ -2151,8 +2153,8 @@ class Router(object):
`dst_id`. If a specific route for `dst_id` is not known, a reference to `dst_id`. If a specific route for `dst_id` is not known, a reference to
the parent context's stream is returned. the parent context's stream is returned.
""" """
return self._stream_by_id.get(dst_id, parent = self._stream_by_id.get(mitogen.parent_id)
self._stream_by_id.get(mitogen.parent_id)) return self._stream_by_id.get(dst_id, parent)
def del_handler(self, handle): def del_handler(self, handle):
""" """
@ -2161,7 +2163,9 @@ class Router(object):
:raises KeyError: :raises KeyError:
The handle wasn't registered. The handle wasn't registered.
""" """
del self._handle_map[handle] _, _, _, respondent = self._handle_map.pop(handle)
if respondent:
self._handles_by_respondent[respondent].discard(handle)
def add_handler(self, fn, handle=None, persist=True, def add_handler(self, fn, handle=None, persist=True,
policy=None, respondent=None): policy=None, respondent=None):
@ -2216,19 +2220,22 @@ class Router(object):
handle = handle or next(self._last_handle) handle = handle or next(self._last_handle)
_vv and IOLOG.debug('%r.add_handler(%r, %r, %r)', self, fn, handle, persist) _vv and IOLOG.debug('%r.add_handler(%r, %r, %r)', self, fn, handle, persist)
self._handle_map[handle] = persist, fn, policy, respondent
if respondent: if respondent:
assert policy is None if respondent not in self._handles_by_respondent:
def policy(msg, _stream): self._handles_by_respondent[respondent] = set()
return msg.is_dead or msg.src_id == respondent.context_id listen(respondent, 'disconnect',
def on_disconnect(): lambda: self._on_respondent_disconnect(respondent))
if handle in self._handle_map: self._handles_by_respondent[respondent].add(handle)
fn(Message.dead())
del self._handle_map[handle]
listen(respondent, 'disconnect', on_disconnect)
self._handle_map[handle] = persist, fn, policy
return handle return handle
def _on_respondent_disconnect(self, context):
for handle in self._handles_by_respondent.pop(context, ()):
_, fn, _, _ = self._handle_map[handle]
fn(Message.dead())
del self._handle_map[handle]
def on_shutdown(self, broker): def on_shutdown(self, broker):
"""Called during :meth:`Broker.shutdown`, informs callbacks registered """Called during :meth:`Broker.shutdown`, informs callbacks registered
with :meth:`add_handle_cb` the connection is dead.""" with :meth:`add_handle_cb` the connection is dead."""
@ -2238,16 +2245,25 @@ class Router(object):
_v and LOG.debug('%r.on_shutdown(): killing %r: %r', self, handle, fn) _v and LOG.debug('%r.on_shutdown(): killing %r: %r', self, handle, fn)
fn(Message.dead()) fn(Message.dead())
def _maybe_send_dead(self, msg):
if msg.reply_to and not msg.is_dead:
msg.reply(Message.dead(), router=self)
refused_msg = 'Refused by policy.' refused_msg = 'Refused by policy.'
def _invoke(self, msg, stream): def _invoke(self, msg, stream):
# IOLOG.debug('%r._invoke(%r)', self, msg) # IOLOG.debug('%r._invoke(%r)', self, msg)
try: try:
persist, fn, policy = self._handle_map[msg.handle] persist, fn, policy, respondent = self._handle_map[msg.handle]
except KeyError: except KeyError:
LOG.error('%r: invalid handle: %r', self, msg) LOG.error('%r: invalid handle: %r', self, msg)
if msg.reply_to and not msg.is_dead: self._maybe_send_dead(msg)
msg.reply(Message.dead()) return
if respondent and not (msg.is_dead or
msg.src_id == respondent.context_id):
LOG.error('%r: reply from unexpected context: %r', self, msg)
self._maybe_send_dead(msg)
return return
if policy and not policy(msg, stream): if policy and not policy(msg, stream):
@ -2261,17 +2277,13 @@ class Router(object):
return return
if not persist: if not persist:
del self._handle_map[msg.handle] self.del_handler(msg.handle)
try: try:
fn(msg) fn(msg)
except Exception: except Exception:
LOG.exception('%r._invoke(%r): %r crashed', self, msg, fn) LOG.exception('%r._invoke(%r): %r crashed', self, msg, fn)
def _maybe_send_dead(self, msg):
if msg.reply_to and not msg.is_dead:
msg.reply(Message.dead(), router=self)
def _async_route(self, msg, in_stream=None): def _async_route(self, msg, in_stream=None):
""" """
Arrange for `msg` to be forwarded towards its destination. If its Arrange for `msg` to be forwarded towards its destination. If its

Loading…
Cancel
Save