@@ -45,6 +45,16 @@ cdef int _process_outputs(libssh.ssh_session session,
45
45
result.stdout += data_b
46
46
return len
47
47
48
+ cdef class ChannelCallback:
49
+ def __cinit__ (self ):
50
+ memset(& self .callback, 0 , sizeof(self .callback))
51
+ callbacks.ssh_callbacks_init(& self .callback)
52
+ self .callback.channel_data_function = < callbacks.ssh_channel_data_callback> & _process_outputs
53
+
54
+ def set_user_data (self , userdata ):
55
+ self ._userdata = userdata
56
+ self .callback.userdata = < void * > self ._userdata
57
+
48
58
cdef class Channel:
49
59
def __cinit__ (self , session ):
50
60
self ._session = session
@@ -159,19 +169,23 @@ cdef class Channel:
159
169
libssh.ssh_channel_free(channel)
160
170
raise LibsshChannelException(" Failed to open_session: [{0}]" .format(rc))
161
171
172
+ result = CompletedProcess(args = command, returncode = - 1 , stdout = b' ' , stderr = b' ' )
173
+
174
+ cb = ChannelCallback()
175
+ cb.set_user_data(result)
176
+ callbacks.ssh_set_channel_callbacks(channel, & cb.callback)
177
+ # keep the callback around in the session object to avoid use after free
178
+ self ._session.push_callback(cb)
179
+
162
180
rc = libssh.ssh_channel_request_exec(channel, command.encode(" utf-8" ))
163
181
if rc != libssh.SSH_OK:
164
182
libssh.ssh_channel_close(channel)
165
183
libssh.ssh_channel_free(channel)
166
184
raise LibsshChannelException(" Failed to execute command [{0}]: [{1}]" .format(command, rc))
167
- result = CompletedProcess(args = command, returncode = - 1 , stdout = b' ' , stderr = b' ' )
168
185
169
- cdef callbacks.ssh_channel_callbacks_struct cb
170
- memset(& cb, 0 , sizeof(cb))
171
- cb.channel_data_function = < callbacks.ssh_channel_data_callback> & _process_outputs
172
- cb.userdata = < void * > result
173
- callbacks.ssh_callbacks_init(& cb)
174
- callbacks.ssh_set_channel_callbacks(channel, & cb)
186
+ # wait before remote writes all data before closing the channel
187
+ while not libssh.ssh_channel_is_eof(channel):
188
+ libssh.ssh_channel_poll(channel, 0 )
175
189
176
190
libssh.ssh_channel_send_eof(channel)
177
191
result.returncode = libssh.ssh_channel_get_exit_status(channel)
0 commit comments