Package paramiko :: Module proxy
[frames] | no frames]

Source Code for Module paramiko.proxy

  1  # Copyright (C) 2012  Yipit, Inc <coders@yipit.com> 
  2  # 
  3  # This file is part of paramiko. 
  4  # 
  5  # Paramiko is free software; you can redistribute it and/or modify it under the 
  6  # terms of the GNU Lesser General Public License as published by the Free 
  7  # Software Foundation; either version 2.1 of the License, or (at your option) 
  8  # any later version. 
  9  # 
 10  # Paramiko is distrubuted in the hope that it will be useful, but WITHOUT ANY 
 11  # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 
 12  # A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more 
 13  # details. 
 14  # 
 15  # You should have received a copy of the GNU Lesser General Public License 
 16  # along with Paramiko; if not, write to the Free Software Foundation, Inc., 
 17  # 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA. 
 18   
 19   
 20  from datetime import datetime 
 21  import os 
 22  from shlex import split as shlsplit 
 23  import signal 
 24  from subprocess import Popen, PIPE 
 25  from select import select 
 26  import socket 
 27   
 28  from paramiko.ssh_exception import ProxyCommandFailure 
 29   
 30   
31 -class ProxyCommand(object):
32 """ 33 Wraps a subprocess running ProxyCommand-driven programs. 34 35 This class implements a the socket-like interface needed by the 36 `.Transport` and `.Packetizer` classes. Using this class instead of a 37 regular socket makes it possible to talk with a Popen'd command that will 38 proxy traffic between the client and a server hosted in another machine. 39 """
40 - def __init__(self, command_line):
41 """ 42 Create a new CommandProxy instance. The instance created by this 43 class can be passed as an argument to the `.Transport` class. 44 45 :param str command_line: 46 the command that should be executed and used as the proxy. 47 """ 48 self.cmd = shlsplit(command_line) 49 self.process = Popen(self.cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE) 50 self.timeout = None 51 self.buffer = []
52
53 - def send(self, content):
54 """ 55 Write the content received from the SSH client to the standard 56 input of the forked command. 57 58 :param str content: string to be sent to the forked command 59 """ 60 try: 61 self.process.stdin.write(content) 62 except IOError as e: 63 # There was a problem with the child process. It probably 64 # died and we can't proceed. The best option here is to 65 # raise an exception informing the user that the informed 66 # ProxyCommand is not working. 67 raise ProxyCommandFailure(' '.join(self.cmd), e.strerror) 68 return len(content)
69
70 - def recv(self, size):
71 """ 72 Read from the standard output of the forked program. 73 74 :param int size: how many chars should be read 75 76 :return: the length of the read content, as an `int` 77 """ 78 try: 79 start = datetime.now() 80 while len(self.buffer) < size: 81 if self.timeout is not None: 82 elapsed = (datetime.now() - start).microseconds 83 timeout = self.timeout * 1000 * 1000 # to microseconds 84 if elapsed >= timeout: 85 raise socket.timeout() 86 r, w, x = select([self.process.stdout], [], [], 0.0) 87 if r and r[0] == self.process.stdout: 88 b = os.read(self.process.stdout.fileno(), 1) 89 # Store in class-level buffer for persistence across 90 # timeouts; this makes us act more like a real socket 91 # (where timeouts don't actually drop data.) 92 self.buffer.append(b) 93 result = ''.join(self.buffer) 94 self.buffer = [] 95 return result 96 except socket.timeout: 97 raise # socket.timeout is a subclass of IOError 98 except IOError as e: 99 raise ProxyCommandFailure(' '.join(self.cmd), e.strerror)
100
101 - def close(self):
102 os.kill(self.process.pid, signal.SIGTERM)
103
104 - def settimeout(self, timeout):
105 self.timeout = timeout
106