Coverage for /pythoncovmergedfiles/medio/medio/src/paramiko/paramiko/proxy.py: 36%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
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 distributed 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# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20import os
21import shlex
22import signal
23from select import select
24import socket
25import time
27# Try-and-ignore import so platforms w/o subprocess (eg Google App Engine) can
28# still import paramiko.
29subprocess, subprocess_import_error = None, None
30try:
31 import subprocess
32except ImportError as e:
33 subprocess_import_error = e
35from paramiko.ssh_exception import ProxyCommandFailure
36from paramiko.util import ClosingContextManager
39class ProxyCommand(ClosingContextManager):
40 """
41 Wraps a subprocess running ProxyCommand-driven programs.
43 This class implements a the socket-like interface needed by the
44 `.Transport` and `.Packetizer` classes. Using this class instead of a
45 regular socket makes it possible to talk with a Popen'd command that will
46 proxy traffic between the client and a server hosted in another machine.
48 Instances of this class may be used as context managers.
49 """
51 def __init__(self, command_line):
52 """
53 Create a new CommandProxy instance. The instance created by this
54 class can be passed as an argument to the `.Transport` class.
56 :param str command_line:
57 the command that should be executed and used as the proxy.
58 """
59 if subprocess is None:
60 raise subprocess_import_error
61 self.cmd = shlex.split(command_line)
62 self.process = subprocess.Popen(
63 self.cmd,
64 stdin=subprocess.PIPE,
65 stdout=subprocess.PIPE,
66 stderr=subprocess.PIPE,
67 bufsize=0,
68 )
69 self.timeout = None
71 def send(self, content):
72 """
73 Write the content received from the SSH client to the standard
74 input of the forked command.
76 :param str content: string to be sent to the forked command
77 """
78 try:
79 self.process.stdin.write(content)
80 except IOError as e:
81 # There was a problem with the child process. It probably
82 # died and we can't proceed. The best option here is to
83 # raise an exception informing the user that the informed
84 # ProxyCommand is not working.
85 raise ProxyCommandFailure(" ".join(self.cmd), e.strerror)
86 return len(content)
88 def recv(self, size):
89 """
90 Read from the standard output of the forked program.
92 :param int size: how many chars should be read
94 :return: the string of bytes read, which may be shorter than requested
95 """
96 try:
97 buffer = b""
98 start = time.time()
99 while len(buffer) < size:
100 select_timeout = None
101 if self.timeout is not None:
102 elapsed = time.time() - start
103 if elapsed >= self.timeout:
104 raise socket.timeout()
105 select_timeout = self.timeout - elapsed
107 r, w, x = select([self.process.stdout], [], [], select_timeout)
108 if r and r[0] == self.process.stdout:
109 buffer += os.read(
110 self.process.stdout.fileno(), size - len(buffer)
111 )
112 return buffer
113 except socket.timeout:
114 if buffer:
115 # Don't raise socket.timeout, return partial result instead
116 return buffer
117 raise # socket.timeout is a subclass of IOError
118 except IOError as e:
119 raise ProxyCommandFailure(" ".join(self.cmd), e.strerror)
121 def close(self):
122 os.kill(self.process.pid, signal.SIGTERM)
124 @property
125 def closed(self):
126 return self.process.returncode is not None
128 @property
129 def _closed(self):
130 # Concession to Python 3 socket-like API
131 return self.closed
133 def settimeout(self, timeout):
134 self.timeout = timeout