Add python-eventlet package to MOS 9.0 repository
[packages/trusty/python-eventlet.git] / python-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 import errno
8 import traceback
9
10 import eventlet
11 from eventlet import hubs
12 from eventlet.support import greenlets, get_errno
13
14 try:
15     sys.ps1
16 except AttributeError:
17     sys.ps1 = '>>> '
18 try:
19     sys.ps2
20 except AttributeError:
21     sys.ps2 = '... '
22
23
24 class FileProxy(object):
25     def __init__(self, f):
26         self.f = f
27
28     def isatty(self):
29         return True
30
31     def flush(self):
32         pass
33
34     def write(self, data, *a, **kw):
35         self.f.write(data, *a, **kw)
36         self.f.flush()
37
38     def readline(self, *a):
39         return self.f.readline(*a).replace('\r\n', '\n')
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         if len(self.hostport) >= 2:
75             host = self.hostport[0]
76             port = self.hostport[1]
77             print("backdoor closed to %s:%s" % (host, port,))
78         else:
79             print('backdoor closed')
80
81
82 def backdoor_server(sock, locals=None):
83     """ Blocking function that runs a backdoor server on the socket *sock*,
84     accepting connections and running backdoor consoles for each client that
85     connects.
86
87     The *locals* argument is a dictionary that will be included in the locals()
88     of the interpreters.  It can be convenient to stick important application
89     variables in here.
90     """
91     listening_on = sock.getsockname()
92     if sock.family == socket.AF_INET:
93         # Expand result to IP + port
94         listening_on = '%s:%s' % listening_on
95     elif sock.family == socket.AF_INET6:
96         ip, port, _, _ = listening_on
97         listening_on = '%s:%s' % (ip, port,)
98     # No action needed if sock.family == socket.AF_UNIX
99
100     print("backdoor server listening on %s" % (listening_on,))
101     try:
102         try:
103             while True:
104                 socketpair = sock.accept()
105                 backdoor(socketpair, locals)
106         except socket.error as e:
107             # Broken pipe means it was shutdown
108             if get_errno(e) != errno.EPIPE:
109                 raise
110     finally:
111         sock.close()
112
113
114 def backdoor(conn_info, locals=None):
115     """Sets up an interactive console on a socket with a single connected
116     client.  This does not block the caller, as it spawns a new greenlet to
117     handle the console.  This is meant to be called from within an accept loop
118     (such as backdoor_server).
119     """
120     conn, addr = conn_info
121     if conn.family == socket.AF_INET:
122         host, port = addr
123         print("backdoor to %s:%s" % (host, port))
124     elif conn.family == socket.AF_INET6:
125         host, port, _, _ = addr
126         print("backdoor to %s:%s" % (host, port))
127     else:
128         print('backdoor opened')
129     fl = conn.makefile("rw")
130     console = SocketConsole(fl, addr, locals)
131     hub = hubs.get_hub()
132     hub.schedule_call_global(0, console.switch)
133
134
135 if __name__ == '__main__':
136     backdoor_server(eventlet.listen(('127.0.0.1', 9000)), {})