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]

Reply via email to