1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
|
#!/usr/bin/python
#
# Copyright (c) 2008, Thomas Hurst <tom@hur.st>
#
# Use of this file is unrestricted provided this notice is retained.
# If you use it, it'd be nice if you dropped me a note. Also beer.
from terminatorlib.util import dbg, err
from terminatorlib.version import APP_NAME, APP_VERSION
import socket
import threading
import SocketServer
import code
import sys
import readline
import rlcompleter
import re
def ddbg(msg):
# uncomment this to get lots of spam from debugserver
return
dbg(msg)
class PythonConsoleServer(SocketServer.BaseRequestHandler):
env = None
def setup(self):
dbg('debugserver: connect from %s' % str(self.client_address))
ddbg('debugserver: env=%r' % PythonConsoleServer.env)
self.console = TerminatorConsole(PythonConsoleServer.env)
def handle(self):
ddbg("debugserver: handling")
try:
self.socketio = self.request.makefile()
sys.stdout = self.socketio
sys.stdin = self.socketio
sys.stderr = self.socketio
self.console.run(self)
finally:
sys.stdout = sys.__stdout__
sys.stdin = sys.__stdin__
sys.stderr = sys.__stderr__
self.socketio.close()
ddbg("debugserver: done handling")
def verify_request(self, request, client_address):
return True
def finish(self):
ddbg('debugserver: disconnect from %s' % str(self.client_address))
# rfc1116/rfc1184
LINEMODE = chr(34) # Linemode negotiation
NULL = chr(0)
ECHO = chr(1)
CR = chr(13)
LF = chr(10)
SE = chr(240) # End subnegotiation
NOP = chr(241)
DM = chr(242) # Data Mark
BRK = chr(243) # Break
IP = chr(244) # Interrupt Process
AO = chr(245) # Abort Output
AYT = chr(246) # Are You There
EC = chr(247) # Erase Character
EL = chr(248) # Erase Line
GA = chr(249) # Go Ahead
SB = chr(250) # Subnegotiation follows
WILL = chr(251) # Subnegotiation commands
WONT = chr(252)
DO = chr(253)
DONT = chr(254)
IAC = chr(255) # Interpret As Command
UIAC = '(^|[^' + IAC + '])' + IAC # Unescaped IAC
BareLF = re.compile('([^' + CR + '])' + CR)
DoDont = re.compile(UIAC +'[' + DO + DONT + '](.)')
WillWont = re.compile(UIAC + '[' + WILL + WONT + '](.)')
AreYouThere = re.compile(UIAC + AYT)
IpTelnet = re.compile(UIAC + IP)
OtherTelnet = re.compile(UIAC + '[^' + IAC + ']')
# See http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/205335 for telnet bits
# Python doesn't make this an especially neat conversion :(
class TerminatorConsole(code.InteractiveConsole):
def parse_telnet(self, data):
odata = data
data = re.sub(BareLF, '\\1', data)
data = data.replace(CR + NULL, '')
data = data.replace(NULL, '')
bits = re.findall(DoDont, data)
ddbg("bits = %r" % bits)
if bits:
data = re.sub(DoDont, '\\1', data)
ddbg("telnet: DO/DON'T answer")
# answer DO and DON'T with WON'T
for bit in bits:
self.write(IAC + WONT + bit[1])
bits = re.findall(WillWont, data)
if bits:
data = re.sub(WillWont, '\\1', data)
ddbg("telnet: WILL/WON'T answer")
for bit in bits:
# answer WILLs and WON'T with DON'Ts
self.write(IAC + DONT + bit[1])
bits = re.findall(AreYouThere, data)
if bits:
ddbg("telnet: am I there answer")
data = re.sub(AreYouThere, '\\1', data)
for bit in bits:
self.write("Yes, I'm still here, I think.\n")
(data, interrupts) = re.subn(IpTelnet, '\\1', data)
if interrupts:
ddbg("debugserver: Ctrl-C detected")
raise KeyboardInterrupt
data = re.sub(OtherTelnet, '\\1', data) # and any other Telnet codes
data = data.replace(IAC + IAC, IAC) # and handle escapes
if data != odata:
ddbg("debugserver: Replaced %r with %r" % (odata, data))
return data
def raw_input(self, prompt = None):
ddbg("debugserver: raw_input prompt = %r" % prompt)
if prompt:
self.write(prompt)
buf = ''
compstate = 0
while True:
data = self.server.socketio.read(1)
ddbg('raw_input: char=%r' % data)
if data == LF or data == '\006':
buf = self.parse_telnet(buf + data)
if buf != '':
return buf
elif data == '\004' or data == '': # ^D
raise EOFError
else:
buf += data
def write(self, data):
ddbg("debugserver: write %r" % data)
self.server.socketio.write(data)
self.server.socketio.flush()
def run(self, server):
self.server = server
self.write("Welcome to the %s-%s debug server, have a nice stay\n" % (APP_NAME, APP_VERSION))
self.interact()
try:
self.write("Time to go. Bye!\n")
except:
pass
def spawn(env):
PythonConsoleServer.env = env
tcpserver = SocketServer.TCPServer(('127.0.0.1', 0), PythonConsoleServer)
dbg("debugserver: listening on %s" % str(tcpserver.server_address))
debugserver = threading.Thread(target=tcpserver.serve_forever, name="DebugServer")
debugserver.setDaemon(True)
debugserver.start()
return(debugserver, tcpserver)
|