File: debugserver.py

package info (click to toggle)
terminator 0.93-1
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 1,672 kB
  • ctags: 980
  • sloc: python: 7,551; sh: 22; makefile: 12
file content (174 lines) | stat: -rw-r--r-- 5,015 bytes parent folder | download | duplicates (3)
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)