Skip to content

Commit c49b27e

Browse files
author
Pan
committed
Implemented channel functions, added channel tests.
Added exceptions and error code handling functions.
1 parent 84fa52d commit c49b27e

File tree

9 files changed

+471
-3
lines changed

9 files changed

+471
-3
lines changed

ssh/channel.pxd

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# This file is part of ssh-python.
2+
# Copyright (C) 2018 Panos Kittenis
3+
#
4+
# This library is free software; you can redistribute it and/or
5+
# modify it under the terms of the GNU Lesser General Public
6+
# License as published by the Free Software Foundation, version 2.1.
7+
#
8+
# This library is distributed in the hope that it will be useful,
9+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+
# Lesser General Public License for more details.
12+
#
13+
# You should have received a copy of the GNU Lesser General Public
14+
# License along with this library; if not, write to the Free Software
15+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-130
16+
17+
from session cimport Session
18+
19+
cimport c_ssh
20+
21+
22+
cdef class Channel:
23+
cdef c_ssh.ssh_channel _channel
24+
cdef Session session
25+
26+
@staticmethod
27+
cdef Channel from_ptr(c_ssh.ssh_channel _chan, Session session)

ssh/channel.pyx

Lines changed: 312 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
1+
# This file is part of ssh-python.
2+
# Copyright (C) 2018 Panos Kittenis
3+
#
4+
# This library is free software; you can redistribute it and/or
5+
# modify it under the terms of the GNU Lesser General Public
6+
# License as published by the Free Software Foundation, version 2.1.
7+
#
8+
# This library is distributed in the hope that it will be useful,
9+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+
# Lesser General Public License for more details.
12+
#
13+
# You should have received a copy of the GNU Lesser General Public
14+
# License along with this library; if not, write to the Free Software
15+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-130
16+
17+
from libc.stdlib cimport malloc, free
18+
from libc.string cimport const_char
19+
20+
from utils cimport to_bytes, to_str, handle_ssh_error_codes, \
21+
handle_ok_error_codes
22+
23+
cimport c_ssh
24+
25+
26+
cdef class Channel:
27+
28+
def __cinit__(self, Session session):
29+
self.session = session
30+
self._channel = NULL
31+
32+
def __dealloc__(self):
33+
if self._channel is not NULL:
34+
c_ssh.ssh_channel_free(self._channel)
35+
self._channel = NULL
36+
37+
@property
38+
def session(self):
39+
"""The originating session for this channel."""
40+
return self.session
41+
42+
@staticmethod
43+
cdef Channel from_ptr(c_ssh.ssh_channel _chan, Session session):
44+
cdef Channel chan = Channel.__new__(Channel, session)
45+
chan._channel = _chan
46+
return chan
47+
48+
def close(self):
49+
cdef int rc
50+
with nogil:
51+
rc = c_ssh.ssh_channel_close(self._channel)
52+
return handle_ssh_error_codes(rc, self.session._session)
53+
54+
def get_exit_status(self):
55+
cdef int rc
56+
with nogil:
57+
rc = c_ssh.ssh_channel_get_exit_status(self._channel)
58+
return rc
59+
60+
def get_session(self):
61+
return self.session
62+
63+
def is_closed(self):
64+
cdef bint rc
65+
with nogil:
66+
rc = c_ssh.ssh_channel_is_closed(self._channel)
67+
return rc != 0
68+
69+
def is_eof(self):
70+
cdef bint rc
71+
with nogil:
72+
rc = c_ssh.ssh_channel_is_eof(self._channel)
73+
return bool(rc)
74+
75+
def is_open(self):
76+
cdef bint rc
77+
with nogil:
78+
rc = c_ssh.ssh_channel_is_open(self._channel)
79+
return bool(rc)
80+
81+
def send_eof(self):
82+
cdef int rc
83+
with nogil:
84+
rc = c_ssh.ssh_channel_send_eof(self._channel)
85+
return handle_ok_error_codes(rc)
86+
87+
def request_auth_agent(self):
88+
cdef int rc
89+
with nogil:
90+
rc = c_ssh.ssh_channel_request_auth_agent(self._channel)
91+
return handle_ok_error_codes(rc)
92+
93+
def open_auth_agent(self):
94+
cdef int rc
95+
with nogil:
96+
rc = c_ssh.ssh_channel_open_auth_agent(self._channel)
97+
return handle_ok_error_codes(rc)
98+
99+
def open_forward(self, remotehost, int remoteport, sourcehost, int sourceport):
100+
cdef bytes b_remotehost = to_bytes(remotehost)
101+
cdef const_char *c_remotehost = b_remotehost
102+
cdef bytes b_sourcehost = to_bytes(sourcehost)
103+
cdef const_char *c_sourcehost = b_sourcehost
104+
cdef int rc
105+
with nogil:
106+
rc = c_ssh.ssh_channel_open_forward(
107+
self._channel, c_remotehost, remoteport, c_sourcehost, sourceport)
108+
return handle_ok_error_codes(rc)
109+
110+
def open_session(self):
111+
cdef int rc
112+
with nogil:
113+
rc = c_ssh.ssh_channel_open_session(self._channel)
114+
return handle_ok_error_codes(rc)
115+
116+
def open_x11(self, sourcehost, int sourceport):
117+
cdef bytes b_sourcehost = to_bytes(sourcehost)
118+
cdef const_char *c_sourcehost = b_sourcehost
119+
cdef int rc
120+
with nogil:
121+
rc = c_ssh.ssh_channel_open_x11(
122+
self._channel, c_sourcehost, sourceport)
123+
return handle_ok_error_codes(rc)
124+
125+
def accept_x11(self, int timeout_ms):
126+
cdef Channel chan
127+
cdef c_ssh.ssh_channel _chan = NULL
128+
with nogil:
129+
_chan = c_ssh.ssh_channel_accept_x11(self._channel, timeout_ms)
130+
if _chan is NULL:
131+
raise MemoryError
132+
chan = Channel.from_ptr(_chan, self.session)
133+
return chan
134+
135+
def poll(self, bint is_stderr=False):
136+
cdef int rc
137+
with nogil:
138+
rc = c_ssh.ssh_channel_poll(self._channel, is_stderr)
139+
return handle_ok_error_codes(rc)
140+
141+
def poll_timeout(self, int timeout, bint is_stderr=False):
142+
cdef int rc
143+
with nogil:
144+
rc = c_ssh.ssh_channel_poll_timeout(
145+
self._channel, timeout, is_stderr)
146+
return handle_ok_error_codes(rc)
147+
148+
def read(self, c_ssh.uint32_t size=1024, bint is_stderr=False):
149+
cdef int rc
150+
cdef bytes buf = b''
151+
cdef char* cbuf
152+
with nogil:
153+
cbuf = <char *>malloc(sizeof(char)*size)
154+
if cbuf is NULL:
155+
with gil:
156+
raise MemoryError
157+
rc = c_ssh.ssh_channel_read(self._channel, cbuf, size, is_stderr)
158+
try:
159+
if rc > 0:
160+
buf = cbuf[:rc]
161+
finally:
162+
free(cbuf)
163+
return handle_ok_error_codes(rc), buf
164+
165+
def read_nonblocking(self, c_ssh.uint32_t size=1024, bint is_stderr=False):
166+
cdef int rc
167+
cdef bytes buf = b''
168+
cdef char* cbuf
169+
with nogil:
170+
cbuf = <char *>malloc(sizeof(char)*size)
171+
if cbuf is NULL:
172+
with gil:
173+
raise MemoryError
174+
rc = c_ssh.ssh_channel_read_nonblocking(
175+
self._channel, cbuf, size, is_stderr)
176+
try:
177+
if rc > 0:
178+
buf = cbuf[:rc]
179+
finally:
180+
free(cbuf)
181+
return handle_ok_error_codes(rc), buf
182+
183+
def read_timeout(self, int timeout,
184+
c_ssh.uint32_t size=1024, bint is_stderr=False):
185+
cdef int rc
186+
cdef bytes buf = b''
187+
cdef char* cbuf
188+
with nogil:
189+
cbuf = <char *>malloc(sizeof(char)*size)
190+
if cbuf is NULL:
191+
with gil:
192+
raise MemoryError
193+
rc = c_ssh.ssh_channel_read_timeout(
194+
self._channel, cbuf, size, is_stderr, timeout)
195+
try:
196+
if rc > 0:
197+
buf = cbuf[:rc]
198+
finally:
199+
free(cbuf)
200+
return handle_ok_error_codes(rc), buf
201+
202+
def request_env(self, name, value):
203+
cdef bytes b_name = to_bytes(name)
204+
cdef const_char *c_name = b_name
205+
cdef bytes b_value = to_bytes(value)
206+
cdef const_char *c_value = b_value
207+
cdef int rc
208+
with nogil:
209+
rc = c_ssh.ssh_channel_request_env(self._channel, c_name, c_value)
210+
return handle_ok_error_codes(rc)
211+
212+
def request_exec(self, cmd):
213+
cdef bytes b_cmd = to_bytes(cmd)
214+
cdef const_char *c_cmd = b_cmd
215+
cdef int rc
216+
with nogil:
217+
rc = c_ssh.ssh_channel_request_exec(self._channel, c_cmd)
218+
return handle_ok_error_codes(rc)
219+
220+
def request_pty(self):
221+
cdef int rc
222+
with nogil:
223+
rc = c_ssh.ssh_channel_request_pty(self._channel)
224+
return handle_ok_error_codes(rc)
225+
226+
def change_pty_size(self, int cols, int rows):
227+
cdef int rc
228+
with nogil:
229+
rc = c_ssh.ssh_channel_change_pty_size(self._channel, cols, rows)
230+
return handle_ok_error_codes(rc)
231+
232+
def request_pty_size(self, terminal, int col, int row):
233+
cdef bytes b_terminal = to_bytes(terminal)
234+
cdef const_char *c_terminal = b_terminal
235+
cdef int rc
236+
with nogil:
237+
rc = c_ssh.ssh_channel_request_pty_size(
238+
self._channel, c_terminal, col, row)
239+
return handle_ok_error_codes(rc)
240+
241+
def request_send_signal(self, sig):
242+
cdef bytes b_sig = to_bytes(sig)
243+
cdef const_char *c_sig = b_sig
244+
cdef int rc
245+
with nogil:
246+
rc = c_ssh.ssh_channel_request_send_signal(
247+
self._channel, c_sig)
248+
return handle_ok_error_codes(rc)
249+
250+
def request_send_break(self, c_ssh.uint32_t length):
251+
cdef int rc
252+
with nogil:
253+
rc = c_ssh.ssh_channel_request_send_break(
254+
self._channel, length)
255+
return handle_ok_error_codes(rc)
256+
257+
def request_shell(self):
258+
cdef int rc
259+
with nogil:
260+
rc = c_ssh.ssh_channel_request_shell(self._channel)
261+
return handle_ok_error_codes(rc)
262+
263+
def request_sftp(self):
264+
cdef int rc
265+
with nogil:
266+
rc = c_ssh.ssh_channel_request_sftp(self._channel)
267+
return handle_ok_error_codes(rc)
268+
269+
def request_subsystem(self, subsystem):
270+
cdef bytes b_sys = to_bytes(subsystem)
271+
cdef const_char *c_sys = b_sys
272+
cdef int rc
273+
with nogil:
274+
rc = c_ssh.ssh_channel_request_subsystem(
275+
self._channel, c_sys)
276+
return handle_ok_error_codes(rc)
277+
278+
def request_x11(self, int screen_number, bint single_connection=True):
279+
cdef int rc
280+
with nogil:
281+
rc = c_ssh.ssh_channel_request_x11(
282+
self._channel, single_connection, NULL, NULL, screen_number)
283+
return handle_ok_error_codes(rc)
284+
285+
def set_blocking(self, bint blocking):
286+
with nogil:
287+
c_ssh.ssh_channel_set_blocking(self._channel, blocking)
288+
289+
def set_counter(self, counter):
290+
raise NotImplementedError
291+
292+
def write(self, bytes data):
293+
cdef c_ssh.uint32_t size = len(data)
294+
cdef const_char *c_data = data
295+
cdef int rc
296+
with nogil:
297+
rc = c_ssh.ssh_channel_write(self._channel, c_data, size)
298+
return handle_ok_error_codes(rc)
299+
300+
def write_stderr(self, bytes data):
301+
cdef c_ssh.uint32_t size = len(data)
302+
cdef const_char *c_data = data
303+
cdef int rc
304+
with nogil:
305+
rc = c_ssh.ssh_channel_write_stderr(self._channel, c_data, size)
306+
return handle_ok_error_codes(rc)
307+
308+
def window_size(self):
309+
cdef c_ssh.uint32_t size
310+
with nogil:
311+
size = c_ssh.ssh_channel_window_size(self._channel)
312+
return size

ssh/exceptions.pyx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,11 @@ class KeyImportError(BaseSSHError):
5757

5858
class KeyGenerationError(BaseSSHError):
5959
"""Raised on errors generating key"""
60+
61+
62+
class SSHError(BaseSSHError):
63+
"""Raised on SSH errors"""
64+
65+
66+
class EOF(BaseSSHError):
67+
"""Raised on EOF errors"""

ssh/session.pyx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ from cpython cimport PyObject_AsFileDescriptor
1818
from libc.stdlib cimport malloc, free
1919
from libc.string cimport const_char
2020

21+
from channel cimport Channel
2122
from utils cimport to_bytes, to_str, handle_ssh_error_codes, \
2223
handle_auth_error_codes
2324
from options cimport Option
@@ -47,10 +48,13 @@ cdef class Session:
4748
rc = c_ssh.ssh_blocking_flush(self._session, timeout)
4849
return handle_ssh_error_codes(rc, self._session)
4950

50-
def new_channel(self):
51+
def channel_new(self):
5152
cdef c_ssh.ssh_channel _channel
53+
cdef Channel channel
5254
with nogil:
5355
_channel = c_ssh.ssh_channel_new(self._session)
56+
channel = Channel.from_ptr(_channel, self)
57+
return channel
5458

5559
def connect(self):
5660
cdef int rc

ssh/utils.pxd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,6 @@
1717
cdef bytes to_bytes(_str)
1818
cdef object to_str(char *c_str)
1919
cdef object to_str_len(char *c_str, int length)
20+
cdef int handle_ok_error_codes(int errcode) except -1
2021
cdef int handle_ssh_error_codes(int errcode, void *caller) except -1
2122
cdef int handle_auth_error_codes(int errcode, void *caller) except -1

0 commit comments

Comments
 (0)