diff --git a/mitogen/__init__.py b/mitogen/__init__.py index c6974199..0ba9d90e 100644 --- a/mitogen/__init__.py +++ b/mitogen/__init__.py @@ -31,3 +31,8 @@ context_id = 0 #: This is ``None`` in a master, otherwise it is the master-generated ID unique #: to the slave's parent context. parent_id = None + + +#: This is an empty list in a master, otherwise it is a list of parent context +#: IDs ordered from most direct to least direct. +parent_ids = [] diff --git a/mitogen/core.py b/mitogen/core.py index 65432062..ab862609 100644 --- a/mitogen/core.py +++ b/mitogen/core.py @@ -49,6 +49,10 @@ class Error(Exception): Exception.__init__(self, fmt) +class SecurityError(Error): + pass + + class CallError(Error): def __init__(self, e): s = '%s.%s: %s' % (type(e).__module__, type(e).__name__, e) @@ -1156,7 +1160,7 @@ class ExternalContext(object): self.importer = Importer(self.parent, core_src) sys.meta_path.append(self.importer) - def _setup_package(self, context_id, parent_id): + def _setup_package(self, context_id, parent_ids): global mitogen mitogen = imp.new_module('mitogen') mitogen.__package__ = 'mitogen' @@ -1164,7 +1168,8 @@ class ExternalContext(object): mitogen.__loader__ = self.importer mitogen.is_master = False mitogen.context_id = context_id - mitogen.parent_id = parent_id + mitogen.parent_ids = parent_ids + mitogen.parent_id = parent_ids[0] mitogen.core = sys.modules['__main__'] mitogen.core.__file__ = 'x/mitogen/core.py' # For inspect.getsource() mitogen.core.__loader__ = self.importer @@ -1187,8 +1192,10 @@ class ExternalContext(object): def _dispatch_calls(self): for msg, data in self.channel: LOG.debug('_dispatch_calls(%r)', data) - modname, klass, func, args, kwargs = data + if msg.src_id not in mitogen.parent_ids: + LOG.warning('CALL_FUNCTION from non-parent %r', msg.src_id) + modname, klass, func, args, kwargs = data try: obj = __import__(modname, {}, {}, ['']) if klass: @@ -1209,14 +1216,14 @@ class ExternalContext(object): Message.pickled(e, dst_id=msg.src_id, handle=msg.reply_to) ) - def main(self, parent_id, context_id, debug, profiling, log_level, + def main(self, parent_ids, context_id, debug, profiling, log_level, in_fd=100, out_fd=1, core_src_fd=101, setup_stdio=True): - self._setup_master(profiling, parent_id, context_id, in_fd, out_fd) + self._setup_master(profiling, parent_ids[0], context_id, in_fd, out_fd) try: try: self._setup_logging(debug, log_level) self._setup_importer(core_src_fd) - self._setup_package(context_id, parent_id) + self._setup_package(context_id, parent_ids) if setup_stdio: self._setup_stdio() diff --git a/mitogen/fakessh.py b/mitogen/fakessh.py index 69540ef5..bff53dbb 100644 --- a/mitogen/fakessh.py +++ b/mitogen/fakessh.py @@ -369,6 +369,9 @@ def run(dest, router, args, deadline=None, econtext=None): # Held in socket buffer until process is booted. fakessh.call_async(_fakessh_main, dest.context_id) + parent_ids = mitogen.parent_ids[:] + parent_ids.insert(0, mitogen.context_id) + tmp_path = tempfile.mkdtemp(prefix='mitogen_fakessh') try: ssh_path = os.path.join(tmp_path, 'ssh') @@ -378,7 +381,7 @@ def run(dest, router, args, deadline=None, econtext=None): fp.write(inspect.getsource(mitogen.core)) fp.write('\n') fp.write('ExternalContext().main%r\n' % (( - mitogen.context_id, # parent_id + parent_ids, # parent_ids context_id, # context_id router.debug, # debug router.profiling, # profiling diff --git a/mitogen/master.py b/mitogen/master.py index b58eba17..24f0787f 100644 --- a/mitogen/master.py +++ b/mitogen/master.py @@ -625,9 +625,11 @@ class Stream(mitogen.core.Stream): 'exec("%s".decode("base64"))' % (encoded,)] def get_preamble(self): + parent_ids = mitogen.parent_ids[:] + parent_ids.insert(0, mitogen.context_id) source = inspect.getsource(mitogen.core) source += '\nExternalContext().main%r\n' % (( - mitogen.context_id, # parent_id + parent_ids, # parent_ids self.remote_id, # context_id self.debug, self.profiling,