From 674cf3d56349bed44380db2cb72529f797d7ee44 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Mon, 22 Sep 2014 17:59:28 -0400 Subject: move some things around --- pity.py | 94 ------------------------------------------- termcast_client.py | 97 --------------------------------------------- termcast_client/__init__.py | 97 +++++++++++++++++++++++++++++++++++++++++++++ termcast_client/pity.py | 94 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 191 insertions(+), 191 deletions(-) delete mode 100644 pity.py delete mode 100644 termcast_client.py create mode 100644 termcast_client/__init__.py create mode 100644 termcast_client/pity.py diff --git a/pity.py b/pity.py deleted file mode 100644 index 26a9e49..0000000 --- a/pity.py +++ /dev/null @@ -1,94 +0,0 @@ -import fcntl -import os -import pty -import signal -import termios -import tty - -CHILD = pty.CHILD -STDIN_FILENO = pty.STDIN_FILENO -STDOUT_FILENO = pty.STDOUT_FILENO -STDERR_FILENO = pty.STDERR_FILENO - -def fork(handle_window_size=False): - # copied from pty.py, with modifications - master_fd, slave_fd = openpty() - slave_name = os.ttyname(slave_fd) - pid = os.fork() - if pid == CHILD: - # Establish a new session. - os.setsid() - os.close(master_fd) - - if handle_window_size: - clone_window_size_from(slave_name, STDIN_FILENO) - - # Slave becomes stdin/stdout/stderr of child. - os.dup2(slave_fd, STDIN_FILENO) - os.dup2(slave_fd, STDOUT_FILENO) - os.dup2(slave_fd, STDERR_FILENO) - if (slave_fd > STDERR_FILENO): - os.close (slave_fd) - - # Explicitly open the tty to make it become a controlling tty. - tmp_fd = os.open(os.ttyname(STDOUT_FILENO), os.O_RDWR) - os.close(tmp_fd) - else: - os.close(slave_fd) - - # Parent and child process. - return pid, master_fd, slave_name - - -def openpty(): - return pty.openpty() - -def spawn(argv, master_read=pty._read, stdin_read=pty._read, handle_window_size=False): - # copied from pty.py, with modifications - # note that it references a few private functions - would be nice to not - # do that, but you know - if type(argv) == type(''): - argv = (argv,) - pid, master_fd, slave_name = fork(handle_window_size) - if pid == CHILD: - os.execlp(argv[0], *argv) - try: - mode = tty.tcgetattr(STDIN_FILENO) - tty.setraw(STDIN_FILENO) - restore = 1 - except tty.error: # This is the same as termios.error - restore = 0 - - if handle_window_size: - signal.signal( - signal.SIGWINCH, - lambda signum, frame: _winch(slave_name, pid) - ) - - while True: - try: - pty._copy(master_fd, master_read, stdin_read) - except InterruptedError: - continue - except OSError: - if restore: - tty.tcsetattr(STDIN_FILENO, tty.TCSAFLUSH, mode) - break - - os.close(master_fd) - return os.waitpid(pid, 0)[1] - -def clone_window_size_from(slave_name, from_fd): - slave_fd = os.open(slave_name, os.O_RDWR) - try: - fcntl.ioctl( - slave_fd, - termios.TIOCSWINSZ, - fcntl.ioctl(from_fd, termios.TIOCGWINSZ, " " * 1024) - ) - finally: - os.close(slave_fd) - -def _winch(slave_name, child_pid): - clone_window_size_from(slave_name, STDIN_FILENO) - os.kill(child_pid, signal.SIGWINCH) diff --git a/termcast_client.py b/termcast_client.py deleted file mode 100644 index 64e6c2a..0000000 --- a/termcast_client.py +++ /dev/null @@ -1,97 +0,0 @@ -import argparse -import json -import os -import pity -import shutil -import signal -import socket -import sys - -class Client(object): - def __init__(self, host, port, username, password): - self.host = host - self.port = port - self.username = username - self.password = password - - def run(self, argv): - sock = socket.socket() - sock.connect((self.host, self.port)) - sock.send(self._build_connection_string()) - self.winch_set = False - pity.spawn( - argv, - lambda fd: self._master_read(fd, sock), - handle_window_size=True - ) - - def _master_read(self, fd, sock): - if not self.winch_set: - prev_handler = signal.getsignal(signal.SIGWINCH) - signal.signal( - signal.SIGWINCH, - lambda signum, frame: self._winch( - sock, - lambda: prev_handler(signum, frame) - ) - ) - self.winch_set = True - - data = os.read(fd, 1024) - sock.send(data) - return data - - def _winch(self, sock, prev_handler): - prev_handler() - # XXX a bit racy - should try to avoid splitting existing escape - # sequences - sock.send(self._build_winsize_metadata_string()) - - def _build_connection_string(self): - auth = ( - b'hello ' + - self.username.encode('utf-8') + - b' ' + - self.password.encode('utf-8') + - b'\n' - ) - metadata = self._build_connection_metadata_string() - return auth + metadata - - def _build_connection_metadata_string(self): - # for now - return self._build_winsize_metadata_string() - - def _build_winsize_metadata_string(self): - size = shutil.get_terminal_size() - return self._build_metadata_string({ - "geometry": [ size.columns, size.lines ], - }) - - def _build_metadata_string(self, data): - return b'\033]499;' + json.dumps(data).encode('utf-8') + b'\007' - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('--host', default="noway.ratry.ru") - parser.add_argument('--port', type=int, default=31337) - parser.add_argument('--username', default=os.getenv("USER")) - parser.add_argument('--password', default="asdf") - parser.add_argument( - 'command', - nargs=argparse.REMAINDER, - ) - - args = parser.parse_args(sys.argv[1:]) - - client = Client( - host=args.host, - port=args.port, - username=args.username, - password=args.password, - ) - - command = args.command - if len(args.command) < 1: - command = os.getenv("SHELL", default="/bin/sh") - client.run(command) diff --git a/termcast_client/__init__.py b/termcast_client/__init__.py new file mode 100644 index 0000000..64e6c2a --- /dev/null +++ b/termcast_client/__init__.py @@ -0,0 +1,97 @@ +import argparse +import json +import os +import pity +import shutil +import signal +import socket +import sys + +class Client(object): + def __init__(self, host, port, username, password): + self.host = host + self.port = port + self.username = username + self.password = password + + def run(self, argv): + sock = socket.socket() + sock.connect((self.host, self.port)) + sock.send(self._build_connection_string()) + self.winch_set = False + pity.spawn( + argv, + lambda fd: self._master_read(fd, sock), + handle_window_size=True + ) + + def _master_read(self, fd, sock): + if not self.winch_set: + prev_handler = signal.getsignal(signal.SIGWINCH) + signal.signal( + signal.SIGWINCH, + lambda signum, frame: self._winch( + sock, + lambda: prev_handler(signum, frame) + ) + ) + self.winch_set = True + + data = os.read(fd, 1024) + sock.send(data) + return data + + def _winch(self, sock, prev_handler): + prev_handler() + # XXX a bit racy - should try to avoid splitting existing escape + # sequences + sock.send(self._build_winsize_metadata_string()) + + def _build_connection_string(self): + auth = ( + b'hello ' + + self.username.encode('utf-8') + + b' ' + + self.password.encode('utf-8') + + b'\n' + ) + metadata = self._build_connection_metadata_string() + return auth + metadata + + def _build_connection_metadata_string(self): + # for now + return self._build_winsize_metadata_string() + + def _build_winsize_metadata_string(self): + size = shutil.get_terminal_size() + return self._build_metadata_string({ + "geometry": [ size.columns, size.lines ], + }) + + def _build_metadata_string(self, data): + return b'\033]499;' + json.dumps(data).encode('utf-8') + b'\007' + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--host', default="noway.ratry.ru") + parser.add_argument('--port', type=int, default=31337) + parser.add_argument('--username', default=os.getenv("USER")) + parser.add_argument('--password', default="asdf") + parser.add_argument( + 'command', + nargs=argparse.REMAINDER, + ) + + args = parser.parse_args(sys.argv[1:]) + + client = Client( + host=args.host, + port=args.port, + username=args.username, + password=args.password, + ) + + command = args.command + if len(args.command) < 1: + command = os.getenv("SHELL", default="/bin/sh") + client.run(command) diff --git a/termcast_client/pity.py b/termcast_client/pity.py new file mode 100644 index 0000000..26a9e49 --- /dev/null +++ b/termcast_client/pity.py @@ -0,0 +1,94 @@ +import fcntl +import os +import pty +import signal +import termios +import tty + +CHILD = pty.CHILD +STDIN_FILENO = pty.STDIN_FILENO +STDOUT_FILENO = pty.STDOUT_FILENO +STDERR_FILENO = pty.STDERR_FILENO + +def fork(handle_window_size=False): + # copied from pty.py, with modifications + master_fd, slave_fd = openpty() + slave_name = os.ttyname(slave_fd) + pid = os.fork() + if pid == CHILD: + # Establish a new session. + os.setsid() + os.close(master_fd) + + if handle_window_size: + clone_window_size_from(slave_name, STDIN_FILENO) + + # Slave becomes stdin/stdout/stderr of child. + os.dup2(slave_fd, STDIN_FILENO) + os.dup2(slave_fd, STDOUT_FILENO) + os.dup2(slave_fd, STDERR_FILENO) + if (slave_fd > STDERR_FILENO): + os.close (slave_fd) + + # Explicitly open the tty to make it become a controlling tty. + tmp_fd = os.open(os.ttyname(STDOUT_FILENO), os.O_RDWR) + os.close(tmp_fd) + else: + os.close(slave_fd) + + # Parent and child process. + return pid, master_fd, slave_name + + +def openpty(): + return pty.openpty() + +def spawn(argv, master_read=pty._read, stdin_read=pty._read, handle_window_size=False): + # copied from pty.py, with modifications + # note that it references a few private functions - would be nice to not + # do that, but you know + if type(argv) == type(''): + argv = (argv,) + pid, master_fd, slave_name = fork(handle_window_size) + if pid == CHILD: + os.execlp(argv[0], *argv) + try: + mode = tty.tcgetattr(STDIN_FILENO) + tty.setraw(STDIN_FILENO) + restore = 1 + except tty.error: # This is the same as termios.error + restore = 0 + + if handle_window_size: + signal.signal( + signal.SIGWINCH, + lambda signum, frame: _winch(slave_name, pid) + ) + + while True: + try: + pty._copy(master_fd, master_read, stdin_read) + except InterruptedError: + continue + except OSError: + if restore: + tty.tcsetattr(STDIN_FILENO, tty.TCSAFLUSH, mode) + break + + os.close(master_fd) + return os.waitpid(pid, 0)[1] + +def clone_window_size_from(slave_name, from_fd): + slave_fd = os.open(slave_name, os.O_RDWR) + try: + fcntl.ioctl( + slave_fd, + termios.TIOCSWINSZ, + fcntl.ioctl(from_fd, termios.TIOCGWINSZ, " " * 1024) + ) + finally: + os.close(slave_fd) + +def _winch(slave_name, child_pid): + clone_window_size_from(slave_name, STDIN_FILENO) + os.kill(child_pid, signal.SIGWINCH) -- cgit v1.2.3