Skip to content

Commit eb09a16

Browse files
committed
Send EOF on channel Close (Fixes #143, #496, #553, #554)
Signed-off-by: Jeroen van Erp <[email protected]>
1 parent 53d241e commit eb09a16

File tree

2 files changed

+24
-14
lines changed

2 files changed

+24
-14
lines changed

src/main/java/net/schmizz/sshj/connection/channel/ChannelOutputStream.java

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
import java.io.IOException;
2424
import java.io.OutputStream;
25+
import java.util.concurrent.atomic.AtomicBoolean;
2526

2627
/**
2728
* {@link OutputStream} for channels. Buffers data upto the remote window's maximum packet size. Data can also be
@@ -36,7 +37,7 @@ public final class ChannelOutputStream extends OutputStream implements ErrorNoti
3637
private final DataBuffer buffer = new DataBuffer();
3738
private final byte[] b = new byte[1];
3839

39-
private boolean closed;
40+
private AtomicBoolean closed;
4041
private SSHException error;
4142

4243
private final class DataBuffer {
@@ -122,6 +123,7 @@ public ChannelOutputStream(Channel chan, Transport trans, Window.Remote win) {
122123
this.chan = chan;
123124
this.trans = trans;
124125
this.win = win;
126+
this.closed = new AtomicBoolean(false);
125127
}
126128

127129
@Override
@@ -151,24 +153,21 @@ public synchronized void notifyError(SSHException error) {
151153

152154
private void checkClose() throws SSHException {
153155
// Check whether either the Stream is closed, or the underlying channel is closed
154-
if (closed || !chan.isOpen()) {
155-
if (error != null)
156+
if (closed.get() || !chan.isOpen()) {
157+
if (error != null) {
156158
throw error;
157-
else
159+
} else {
158160
throw new ConnectionException("Stream closed");
161+
}
159162
}
160163
}
161164

162165
@Override
163166
public synchronized void close() throws IOException {
164167
// Not closed yet, and underlying channel is open to flush the data to.
165-
if (!closed && chan.isOpen()) {
166-
try {
167-
buffer.flush(false);
168-
// trans.write(new SSHPacket(Message.CHANNEL_EOF).putUInt32(chan.getRecipient()));
169-
} finally {
170-
closed = true;
171-
}
168+
if (!closed.getAndSet(true) && chan.isOpen()) {
169+
buffer.flush(false);
170+
trans.write(new SSHPacket(Message.CHANNEL_EOF).putUInt32(chan.getRecipient()));
172171
}
173172
}
174173

src/test/java/net/schmizz/sshj/LoadsOfConnects.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
import org.slf4j.Logger;
2121
import org.slf4j.LoggerFactory;
2222

23+
import net.schmizz.sshj.common.IOUtils;
24+
import net.schmizz.sshj.connection.channel.direct.Session;
25+
2326
import static org.junit.Assert.fail;
2427

2528
public class LoadsOfConnects {
@@ -31,15 +34,23 @@ public class LoadsOfConnects {
3134
@Test
3235
public void loadsOfConnects() {
3336
try {
37+
fixture.start();
3438
for (int i = 0; i < 1000; i++) {
3539
log.info("Try " + i);
36-
fixture.start();
37-
fixture.setupConnectedDefaultClient();
40+
SSHClient client = fixture.setupConnectedDefaultClient();
41+
client.authPassword("test", "test");
42+
Session s = client.startSession();
43+
Session.Command c = s.exec("ls");
44+
IOUtils.readFully(c.getErrorStream());
45+
IOUtils.readFully(c.getInputStream());
46+
c.close();
47+
s.close();
3848
fixture.stopClient();
39-
fixture.stopServer();
4049
}
4150
} catch (Exception e) {
4251
fail(e.getMessage());
52+
} finally {
53+
fixture.stopServer();
4354
}
4455

4556
}

0 commit comments

Comments
 (0)