Add python-eventlet 0.16.1
[packages/trusty/python-eventlet.git] / eventlet / eventlet / backdoor.py
1 from __future__ import print_function
2
3 from code import InteractiveConsole
4 import errno
5 import socket
6 import sys
7
8 import eventlet
9 from eventlet import hubs
10 from eventlet.support import greenlets, get_errno
11
12 try:
13     sys.ps1
14 except AttributeError:
15     sys.ps1 = '>>> '
16 try:
17     sys.ps2
18 except AttributeError:
19     sys.ps2 = '... '
20
21
22 class FileProxy(object):
23     def __init__(self, f):
24         self.f = f
25
26     def isatty(self):
27         return True
28
29     def flush(self):
30         pass
31
32     def write(self, data, *a, **kw):
33         self.f.write(data, *a, **kw)
34         self.f.flush()
35
36     def readline(self, *a):
37         return self.f.readline(*a).replace('\r\n', '\n')
38
39     def __getattr__(self, attr):
40         return getattr(self.f, attr)
41
42
43 # @@tavis: the `locals` args below mask the built-in function.  Should
44 # be renamed.
45 class SocketConsole(greenlets.greenlet):
46     def __init__(self, desc, hostport, locals):
47         self.hostport = hostport
48         self.locals = locals
49         # mangle the socket
50         self.desc = FileProxy(desc)
51         greenlets.greenlet.__init__(self)
52
53     def run(self):
54         try:
55             console = InteractiveConsole(self.locals)
56             console.interact()
57         finally:
58             self.switch_out()
59             self.finalize()
60
61     def switch(self, *args, **kw):
62         self.saved = sys.stdin, sys.stderr, sys.stdout
63         sys.stdin = sys.stdout = sys.stderr = self.desc
64         greenlets.greenlet.switch(self, *args, **kw)
65
66     def switch_out(self):
67         sys.stdin, sys.stderr, sys.stdout = self.saved
68
69     def finalize(self):
70         # restore the state of the socket
71         self.desc = None
72         print("backdoor closed to %s:%s" % self.hostport)
73
74
75 def backdoor_server(sock, locals=None):
76     """ Blocking function that runs a backdoor server on the socket *sock*,
77     accepting connections and running backdoor consoles for each client that
78     connects.
79
80     The *locals* argument is a dictionary that will be included in the locals()
81     of the interpreters.  It can be convenient to stick important application
82     variables in here.
83     """
84     print("backdoor server listening on %s:%s" % sock.getsockname())
85     try:
86         try:
87             while True:
88                 socketpair = sock.accept()
89                 backdoor(socketpair, locals)
90         except socket.error as e:
91             # Broken pipe means it was shutdown
92             if get_errno(e) != errno.EPIPE:
93                 raise
94     finally:
95         sock.close()
96
97
98 def backdoor(conn_info, locals=None):
99     """Sets up an interactive console on a socket with a single connected
100     client.  This does not block the caller, as it spawns a new greenlet to
101     handle the console.  This is meant to be called from within an accept loop
102     (such as backdoor_server).
103     """
104     conn, addr = conn_info
105     host, port = addr
106     print("backdoor to %s:%s" % (host, port))
107     fl = conn.makefile("rw")
108     console = SocketConsole(fl, (host, port), locals)
109     hub = hubs.get_hub()
110     hub.schedule_call_global(0, console.switch)
111
112
113 if __name__ == '__main__':
114     backdoor_server(eventlet.listen(('127.0.0.1', 9000)), {})