0

I'm making a lightweight manhole-like remote interactive Python shell by setting stdin, stdout, stderr to a socket and then calling code.interact().

This works beautifully except for arrow keys showing up like ^[[C when I connect to it via nc localhost 1337.

It's not an issue of not having readline installed, as that works fine when I launch the interpreter manually, even if I run code.interact(). The issue only occurs through sockets. I can import readline inside my remote shell but that does nothing.

Perhaps I'm missing something related to readline in SocketWrapper.read()?

import socket
import sys
import readline
readline.parse_and_bind('tab: complete') # doesn't work
import code

port = 1337

while True:
    sock = socket.socket()
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind(('', port))
    sock.listen(1)
    print("~Listening on port %d~" % port)
    connection, connection_addr = sock.accept()
    print("Accepted connection from %s." % (connection_addr,))

    class SocketWrapper:
        def __init__(self, sock):
            self.sock = sock

        def read(self, length):
            return self.sock.recv(length)

        def write(self, text):
            return self.sock.send(text)

        def readline(self):
            return self.sock.makefile().readline()

    sockfile = SocketWrapper(connection)

    sys.stdin = sockfile
    sys.stdout = sockfile
    sys.stderr = sockfile

    code.interact(
        local=dict(globals(), **locals())
    )
Dmiters
  • 2,011
  • 3
  • 23
  • 31
  • 1
    I'm pretty sure line completion has to happen on the *other* side of the socket. – user2357112 Jul 25 '17 at 21:56
  • @user2357112 Hmm why is that? Does that mean that it's impossible to do line editing if the client is merely a netcat instance? If I can use backspace, I don't see why arrow keys are any less feasible. – Dmiters Jul 25 '17 at 22:08
  • 1
    Backspace is handled on the other side of the socket. – user2357112 Jul 25 '17 at 22:09
  • Hmmm but perhaps I could pull some shenanigans with carriage returns to simply rewrite the current line with e.g. the previous input when is pressed. Integrating that with the Python interpreter is the part I'm lost on though. – Dmiters Jul 25 '17 at 22:22
  • 1
    Python has no idea that the up arrow key was pressed. That's all happening on the other side of the socket. – user2357112 Jul 25 '17 at 22:24
  • Ahhhh I see now. However, if I run ` stty -icanon && nc [...]` as suggested [here](https://superuser.com/a/429134/197038), sys.stdout.read(1) returns on the first character (even if I press up arrow), and pressing backspace sends `^?`. – Dmiters Jul 25 '17 at 22:33
  • 1
    With that, you could probably make Python perform line completion over the socket, but I don't think the `readline` module will do that for you. I'm pretty sure the underlying C library is hooked up to the C-level stdin and stdout, without any option exposed for Python code to change that. – user2357112 Jul 25 '17 at 23:03

0 Answers0