Skip to content

Commit 9dcc72a

Browse files
author
Pan
committed
Updated session and channel to not disconnect session prior to freeing channel and keep track of channel close status. Updated tests.
1 parent 0931e21 commit 9dcc72a

File tree

6 files changed

+41
-23
lines changed

6 files changed

+41
-23
lines changed

ssh/channel.pxd

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ cimport c_ssh
2121

2222
cdef class Channel:
2323
cdef c_ssh.ssh_channel _channel
24-
cdef Session session
24+
cdef readonly Session session
25+
cdef readonly bint closed
2526

2627
@staticmethod
2728
cdef Channel from_ptr(c_ssh.ssh_channel _chan, Session session)

ssh/channel.pyx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,15 @@ cdef class Channel:
2727

2828
def __cinit__(self, Session session):
2929
self.session = session
30+
self.closed = False
3031

3132
def __dealloc__(self):
3233
if self._channel is not NULL:
34+
if not self.closed:
35+
c_ssh.ssh_channel_close(self._channel)
3336
c_ssh.ssh_channel_free(self._channel)
3437
self._channel = NULL
3538

36-
@property
37-
def session(self):
38-
"""The originating session for this channel."""
39-
return self.session
40-
4139
@staticmethod
4240
cdef Channel from_ptr(c_ssh.ssh_channel _chan, Session session):
4341
cdef Channel chan = Channel.__new__(Channel, session)
@@ -46,8 +44,12 @@ cdef class Channel:
4644

4745
def close(self):
4846
cdef int rc
47+
if self.closed:
48+
return 0
4949
with nogil:
5050
rc = c_ssh.ssh_channel_close(self._channel)
51+
if rc == 0:
52+
self.closed = True
5153
return handle_ssh_error_codes(rc, self.session._session)
5254

5355
def get_exit_status(self):
@@ -144,7 +146,7 @@ cdef class Channel:
144146
self._channel, timeout, is_stderr)
145147
return handle_ok_error_codes(rc)
146148

147-
def read(self, c_ssh.uint32_t size=1024, bint is_stderr=False):
149+
def read(self, c_ssh.uint32_t size=1024*1024, bint is_stderr=False):
148150
cdef int rc
149151
cdef bytes buf = b''
150152
cdef char* cbuf
@@ -161,7 +163,7 @@ cdef class Channel:
161163
free(cbuf)
162164
return handle_ok_error_codes(rc), buf
163165

164-
def read_nonblocking(self, c_ssh.uint32_t size=1024, bint is_stderr=False):
166+
def read_nonblocking(self, c_ssh.uint32_t size=1024*1024, bint is_stderr=False):
165167
cdef int rc
166168
cdef bytes buf = b''
167169
cdef char* cbuf
@@ -180,7 +182,7 @@ cdef class Channel:
180182
return handle_ok_error_codes(rc), buf
181183

182184
def read_timeout(self, int timeout,
183-
c_ssh.uint32_t size=1024, bint is_stderr=False):
185+
c_ssh.uint32_t size=1024*1024, bint is_stderr=False):
184186
cdef int rc
185187
cdef bytes buf = b''
186188
cdef char* cbuf

ssh/helper.pyx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# This file is part of ssh-python.
2-
# Copyright (C) 2017-2018 Panos Kittenis
2+
# Copyright (C) 2018 Panos Kittenis
33
#
44
# This library is free software; you can redistribute it and/or
55
# modify it under the terms of the GNU Lesser General Public

ssh/session.pyx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ cdef class Session:
5757

5858
def __dealloc__(self):
5959
if self._session is not NULL:
60+
if c_ssh.ssh_is_connected(self._session):
61+
c_ssh.ssh_disconnect(self._session)
6062
c_ssh.ssh_free(self._session)
6163
self._session = NULL
6264

@@ -129,10 +131,12 @@ cdef class Session:
129131
return handle_ssh_error_codes(rc, self._session)
130132

131133
def disconnect(self):
132-
if self._session is NULL:
133-
return
134-
with nogil:
135-
c_ssh.ssh_disconnect(self._session)
134+
"""No-op. Handled by object de-allocation."""
135+
pass
136+
# if not c_ssh.ssh_is_connected(self._session):
137+
# return
138+
# with nogil:
139+
# c_ssh.ssh_disconnect(self._session)
136140

137141
def connector_new(self):
138142
cdef c_ssh.ssh_connector _connector

tests/test_channel.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,20 @@
2626

2727
class ChannelTest(SSHTestCase):
2828

29+
def test_close(self):
30+
self._auth()
31+
chan = self.session.channel_new()
32+
self.assertEqual(chan.open_session(), 0)
33+
self.assertFalse(chan.closed)
34+
chan.request_exec('echo me')
35+
chan.read()
36+
self.assertFalse(chan.closed)
37+
chan.close()
38+
self.assertTrue(chan.closed)
39+
chan.close()
40+
self.session.disconnect()
41+
chan.close()
42+
2943
def test_channel_exec(self):
3044
self._auth()
3145
chan = self.session.channel_new()

tests/test_session.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,12 @@ def test_should_not_segfault(self):
5252
session.connector_new()
5353

5454
def test_disconnect(self):
55-
session = Session()
56-
session.options_set(options.HOST, self.host)
57-
session.options_set_port(self.port)
58-
session.options_set(options.USER, self.user)
59-
self.assertEqual(session.connect(), 0)
60-
self.assertEqual(
61-
session.userauth_publickey(self.pkey), 0)
62-
session.disconnect()
63-
del session
55+
self._auth()
56+
chan = self.session.channel_new()
57+
chan.open_session()
58+
chan.close()
59+
self.session.disconnect()
60+
del chan
6461

6562
def test_socket_connect(self):
6663
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

0 commit comments

Comments
 (0)