[project @ Arch-1:robey@lag.net--2003-public%secsh--dev--1.0--patch-150]

when combining stderr with stdout on a channel, merge the buffers too
when turning on combine-stderr mode on a channel, grab the channel lock and
feed any existing stderr buffer into the normal buffer.  this should help
applications (and my unit tests) avoid races between data coming in over
stderr and setting combine-stderr.

_send_eof is now slightly safer too, although i don't think that really fixed
anything.  it just makes me feel better.
This commit is contained in:
Robey Pointer 2005-02-28 07:14:11 +00:00
parent 8ee26cd412
commit 4b8a9d3b7a
1 changed files with 22 additions and 6 deletions

View File

@ -371,8 +371,19 @@ class Channel (object):
@since: 1.1 @since: 1.1
""" """
old = self.combine_stderr data = ''
self.combine_stderr = combine self.lock.acquire()
try:
old = self.combine_stderr
self.combine_stderr = combine
if combine and not old:
# copy old stderr buffer into primary buffer
data = self.in_stderr_buffer
self.in_stderr_buffer = ''
finally:
self.lock.release()
if len(data) > 0:
self._feed(data)
return old return old
@ -762,8 +773,8 @@ class Channel (object):
used to simulate an open FD, but I haven't figured out how to make used to simulate an open FD, but I haven't figured out how to make
pipes enter non-blocking mode on Windows yet. pipes enter non-blocking mode on Windows yet.
""" """
self.lock.acquire()
try: try:
self.lock.acquire()
if self.pipe_rfd != None: if self.pipe_rfd != None:
return self.pipe_rfd return self.pipe_rfd
# create the pipe and feed in any existing data # create the pipe and feed in any existing data
@ -793,7 +804,11 @@ class Channel (object):
# feign "read" shutdown # feign "read" shutdown
self.eof_received = 1 self.eof_received = 1
if (how == 1) or (how == 2): if (how == 1) or (how == 2):
self._send_eof() self.lock.acquire()
try:
self._send_eof()
finally:
self.lock.release()
def shutdown_read(self): def shutdown_read(self):
""" """
@ -963,7 +978,7 @@ class Channel (object):
self.lock.acquire() self.lock.acquire()
try: try:
if not self.eof_received: if not self.eof_received:
self.eof_received = 1 self.eof_received = True
self.in_buffer_cv.notifyAll() self.in_buffer_cv.notifyAll()
self.in_stderr_buffer_cv.notifyAll() self.in_stderr_buffer_cv.notifyAll()
if self.pipe_wfd != None: if self.pipe_wfd != None:
@ -999,13 +1014,14 @@ class Channel (object):
self.out_buffer_cv.notifyAll() self.out_buffer_cv.notifyAll()
def _send_eof(self): def _send_eof(self):
# you are holding the lock.
if self.eof_sent: if self.eof_sent:
return return
m = Message() m = Message()
m.add_byte(chr(MSG_CHANNEL_EOF)) m.add_byte(chr(MSG_CHANNEL_EOF))
m.add_int(self.remote_chanid) m.add_int(self.remote_chanid)
self.transport._send_user_message(m) self.transport._send_user_message(m)
self.eof_sent = 1 self.eof_sent = True
self._log(DEBUG, 'EOF sent') self._log(DEBUG, 'EOF sent')
return return