Adjust the package revision; no actual code changes
[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, six
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         data = six.b(data)
34         self.f.write(data, *a, **kw)
35         self.f.flush()
36
37     def readline(self, *a):
38         line = self.f.readline(*a).replace(b'\r\n', b'\n')
39         return six.u(line)
40
41     def __getattr__(self, attr):
42         return getattr(self.f, attr)
43
44
45 # @@tavis: the `locals` args below mask the built-in function.  Should
46 # be renamed.
47 class SocketConsole(greenlets.greenlet):
48     def __init__(self, desc, hostport, locals):
49         self.hostport = hostport
50         self.locals = locals
51         # mangle the socket
52         self.desc = FileProxy(desc)
53         greenlets.greenlet.__init__(self)
54
55     def run(self):
56         try:
57             console = InteractiveConsole(self.locals)
58             console.interact()
59         finally:
60             self.switch_out()
61             self.finalize()
62
63     def switch(self, *args, **kw):
64         self.saved = sys.stdin, sys.stderr, sys.stdout
65         sys.stdin = sys.stdout = sys.stderr = self.desc
66         greenlets.greenlet.switch(self, *args, **kw)
67
68     def switch_out(self):
69         sys.stdin, sys.stderr, sys.stdout = self.saved
70
71     def finalize(self):
72         # restore the state of the socket
73         self.desc = None
74         print("backdoor closed to %s:%s" % self.hostport)
75
76
77 def backdoor_server(sock, locals=None):
78     """ Blocking function that runs a backdoor server on the socket *sock*,
79     accepting connections and running backdoor consoles for each client that
80     connects.
81
82     The *locals* argument is a dictionary that will be included in the locals()
83     of the interpreters.  It can be convenient to stick important application
84     variables in here.
85     """
86     print("backdoor server listening on %s:%s" % sock.getsockname())
87     try:
88         try:
89             while True:
90                 socketpair = sock.accept()
91                 backdoor(socketpair, locals)
92         except socket.error as e:
93             # Broken pipe means it was shutdown
94             if get_errno(e) != errno.EPIPE:
95                 raise
96     finally:
97         sock.close()
98
99
100 def backdoor(conn_info, locals=None):
101     """Sets up an interactive console on a socket with a single connected
102     client.  This does not block the caller, as it spawns a new greenlet to
103     handle the console.  This is meant to be called from within an accept loop
104     (such as backdoor_server).
105     """
106     conn, addr = conn_info
107     host, port = addr
108     print("backdoor to %s:%s" % (host, port))
109     fl = conn.makefile("rw")
110     console = SocketConsole(fl, (host, port), locals)
111     hub = hubs.get_hub()
112     hub.schedule_call_global(0, console.switch)
113
114
115 if __name__ == '__main__':
116     backdoor_server(eventlet.listen(('127.0.0.1', 9000)), {})