gurka commented on issue #420:
URL: https://github.com/apache/mina-sshd/issues/420#issuecomment-1737355131
Sort of, but it's not pretty. And I weren't able to reproduce it without
also making the "http server" NOT close the socket after a read failure, which
leads me to believe that the root issue is maybe something in our REST service
not cleaning up keep-alive connections that are closed correctly.
Anyway, here is the code that can reproduce this. It's not 100%, but often
after a "http server: read failed, closing connection" you also get the
"ClosedChannelException while shutting down output" INFO log entry. (I used
slf4j-api 2.0.7 and logback-classic 1.4.8 to get logs and be able to control
the root logger level):
Server.java
```
package org.example;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.KeyPairGenerator;
import java.util.List;
import org.apache.sshd.common.util.security.SecurityUtils;
import org.apache.sshd.server.SshServer;
import org.apache.sshd.server.forward.AcceptAllForwardingFilter;
import org.slf4j.LoggerFactory;
public class Server {
public static void main(String[] args) throws IOException,
InterruptedException {
Logger rootLogger = (Logger)
LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
rootLogger.setLevel(Level.INFO);
try (SshServer server = SshServer.setUpDefaultServer()) {
server.setPort(8022);
server.setKeyPairProvider(session -> {
KeyPairGenerator kpg =
SecurityUtils.getKeyPairGenerator("RSA");
kpg.initialize(1024);
return List.of(kpg.generateKeyPair());
});
server.setPasswordAuthenticator((username, password, session) ->
true);
server.setForwardingFilter(new AcceptAllForwardingFilter());
server.start();
while (true) {
// Need to sleep at least 5s, otherwise HttpURLConnection
will re-use the connection
Thread.sleep(10000L);
System.out.println("Connecting to http server via remote
port forwarding tunnel");
try {
HttpURLConnection con = (HttpURLConnection) new
URL("http://localhost:8055/").openConnection();
con.connect();
System.out.println("Request sent");
String response = new
String(con.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
System.out.println("Received response: " + response);
} catch (IOException e) {
System.err.println("Failed: " + e.getMessage());
}
}
}
}
}
```
Client.java
```
package org.example;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import org.apache.sshd.client.SshClient;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.util.net.SshdSocketAddress;
import org.apache.sshd.server.forward.AcceptAllForwardingFilter;
import org.slf4j.LoggerFactory;
public class Client {
public static void main(String[] args) throws IOException {
Logger rootLogger = (Logger)
LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
rootLogger.setLevel(Level.INFO);
try (SshClient sshClient = SshClient.setUpDefaultClient()) {
sshClient.setForwardingFilter(new AcceptAllForwardingFilter());
sshClient.start();
try (ClientSession session = sshClient.connect("test",
"localhost", 8022).verify().getSession()) {
session.addPasswordIdentity("test");
session.auth().verify();
session.startRemotePortForwarding(new
SshdSocketAddress("localhost", 8055),
new SshdSocketAddress("localhost", 8066));
try (ServerSocket ss = new ServerSocket()) {
ss.bind(new InetSocketAddress("localhost", 8066));
System.out.println("http server started");
while (true) {
Socket s = ss.accept();
s.setSoLinger(true, 0);
System.out.println("http server: new connection");
try {
while (true) {
InputStream is = s.getInputStream();
OutputStream os = s.getOutputStream();
// Read request (until two CRLFs)
int[] buffer = new int[4];
int offset = 0;
boolean ok = true;
while (true) {
int read = is.read();
if (read == -1) {
ok = false;
break;
}
buffer[offset % 4] = read;
if (offset >= 4 &&
buffer[offset % 4] == '\n' &&
buffer[(offset - 1) % 4] == '\r'
&&
buffer[(offset - 2) % 4] == '\n'
&&
buffer[(offset - 3) % 4] ==
'\r') {
break;
}
offset += 1;
}
if (!ok) {
System.err.println("http server: read
failed, closing connection");
// Closing the socket here, which would
be the correct action (?), makes the issue in sshd not appear
//s.close();
break;
}
System.out.println("http server: received
request");
StringBuilder sb = new StringBuilder();
sb.append("HTTP/1.1 200 OK\r\n");
sb.append("Connection: Keep-Alive\r\n");
sb.append("Content-Length: 5\r\n");
sb.append("Content-Type: text/plain\r\n");
sb.append("\r\n");
sb.append("hello");
os.write(sb.toString().getBytes(StandardCharsets.UTF_8));
os.flush();
System.out.println("http server: response
sent");
}
} catch (IOException e) {
System.err.println("Socket closed: " +
e.getMessage());
}
}
}
}
}
}
}
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]