# -*- Mode: Python; tab-width: 4 -*- # Copyright 1999 by eGroups, Inc. # # All Rights Reserved # # Permission to use, copy, modify, and distribute this software and # its documentation for any purpose and without fee is hereby # granted, provided that the above copyright notice appear in all # copies and that both that copyright notice and this permission # notice appear in supporting documentation, and that the name of # eGroups not be used in advertising or publicity pertaining to # distribution of the software without specific, written prior # permission. # # EGROUPS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, # INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN # NO EVENT SHALL EGROUPS BE LIABLE FOR ANY SPECIAL, INDIRECT OR # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS # OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. VERSION_STRING = '$Id: backdoor.py,v 1.2 2000/10/06 16:35:36 hassan Exp $' import coro import socket import string import StringIO import sys # TODO: implement multi-line input! # Originally, this object implemented the file-output api, and set # sys.stdout and sys.stderr to 'self'. However, if any other # coroutine ran, it would see the captured definition of sys.stdout, # and would send its output here, instead of the expected place. Now # the code captures all output using StringIO. A little less # flexible, a little less efficient, but much less surprising! # [Note: this is exactly the same problem addressed by Scheme's # dynamic-wind facility] class backdoor: def __init__ (self, socket): self.socket = socket self.buffer = '' self.lines = [] def send (self, data): olb = lb = len(data) while lb: ns = self.socket.send (data) lb = lb - ns return olb def prompt (self): self.send ('>>> ') def read_line (self): if self.lines: l = self.lines[0] self.lines = self.lines[1:] return l else: while not self.lines: block = self.socket.recv (8192) if not block: return None elif block == '\004': self.socket.close() return None else: self.buffer = self.buffer + block lines = string.split (self.buffer, '\r\n') for l in lines[:-1]: self.lines.append (l) self.buffer = lines[-1] return self.read_line() def read_eval_print_loop (self): self.send ('Python ' + sys.version + '\r\n') self.send (sys.copyright + '\r\n') # this does the equivalent of 'from __main__ import *' env = sys.modules['__main__'].__dict__.copy() while 1: self.prompt() line = self.read_line() if line is None: break else: save = sys.stdout, sys.stderr output = StringIO.StringIO() try: try: sys.stdout = sys.stderr = output co = compile (line, repr(self), 'eval') result = eval (co, env) if result is not None: print repr(result) env['_'] = result except SyntaxError: try: co = compile (line, repr(self), 'exec') exec co in env except: import traceback traceback.print_exc() except: import traceback traceback.print_exc() finally: sys.stdout, sys.stderr = save self.send (output.getvalue()) del output def client (conn, addr): b = backdoor (conn) b.read_eval_print_loop() def serve (port=8023): s = coro.coroutine_socket() s.create_socket (socket.AF_INET, socket.SOCK_STREAM) s.set_reuse_addr() s.bind (('', port)) if port == 0: sys.stderr.write("coro.backdoor listening on port: %s\n" % s.socket.getsockname()[1]) s.listen (128) while 1: conn, addr = s.accept() print 'incoming connection from', addr coro.spawn (client, conn, addr) if __name__ == '__main__': coro.spawn (serve) coro.event_loop (30.0)