Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clean ShellFactoryImpl logging, add a test (fixes #1060) #1094

Merged
merged 1 commit into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions remote-ssh/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -30,38 +30,23 @@
import org.jline.terminal.Size;
import org.jline.terminal.Terminal;
import org.jline.terminal.TerminalBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* SSHD {@link org.apache.sshd.server.command.Command} factory which provides access to
* Shell.
*/
public class ShellFactoryImpl implements ShellFactory {

private static final Logger LOGGER = LoggerFactory.getLogger(ShellFactoryImpl.class);

private final Consumer<Ssh.ShellParams> shell;

public ShellFactoryImpl(Consumer<Ssh.ShellParams> shell) {
this.shell = shell;
}

private static void flush(OutputStream... streams) {
for (OutputStream s : streams) {
try {
s.flush();
} catch (IOException e) {
// Ignore
}
}
}

static void close(Closeable... closeables) {
for (Closeable c : closeables) {
try {
c.close();
} catch (IOException e) {
// Ignore
}
}
}

public Command createShell(ChannelSession session) {
return new ShellImpl();
}
Expand Down Expand Up @@ -95,20 +80,13 @@ public void setExitCallback(ExitCallback callback) {

public void start(final ChannelSession session, final Environment env) throws IOException {
try {
new Thread(() -> {
try {
ShellImpl.this.run(session, env);
} catch (Throwable t) {
t.printStackTrace();
}
})
.start();
new Thread(() -> ShellImpl.this.run(session, env)).start();
} catch (Exception e) {
throw new IOException("Unable to start shell", e);
}
}

public void run(ChannelSession session, Environment env) throws Exception {
public void run(ChannelSession session, Environment env) {
try {
Attributes attributes = new Attributes();
for (Map.Entry<PtyMode, Integer> e : env.getPtyModes().entrySet()) {
Expand Down Expand Up @@ -222,7 +200,9 @@ public void run(ChannelSession session, Environment env) throws Exception {

shell.accept(new Ssh.ShellParams(env.getEnv(), session.getSession(), terminal, () -> destroy(session)));
} catch (Throwable t) {
t.printStackTrace();
if (!closed) {
LOGGER.error("Error occured while executing shell", t);
}
}
}

Expand All @@ -235,4 +215,24 @@ public void destroy(ChannelSession session) {
}
}
}

static void flush(OutputStream... streams) {
for (OutputStream s : streams) {
try {
s.flush();
} catch (IOException e) {
LOGGER.debug("Error flushing " + s, e);
}
}
}

static void close(Closeable... closeables) {
for (Closeable c : closeables) {
try {
c.close();
} catch (IOException e) {
LOGGER.debug("Error closing " + c, e);
}
}
}
}
70 changes: 70 additions & 0 deletions remote-ssh/src/test/java/org/jline/builtins/ssh/SshdTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright (c) 2002-2024, the original author(s).
*
* This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software.
*
* https://opensource.org/licenses/BSD-3-Clause
*/
package org.jline.builtins.ssh;

import java.nio.file.Paths;

import org.apache.sshd.client.SshClient;
import org.apache.sshd.client.channel.ChannelShell;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.server.SshServer;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
import org.jline.reader.EndOfFileException;
import org.jline.reader.LineReader;
import org.jline.reader.LineReaderBuilder;
import org.jline.reader.UserInterruptException;
import org.junit.jupiter.api.Test;

public class SshdTest {

@Test
void test() throws Exception {
SshServer sshd = SshServer.setUpDefaultServer();
sshd.setPort(0);
sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(Paths.get("target/hostkey.ser")));
sshd.setPasswordAuthenticator((username, password, session) -> true);
sshd.setShellFactory(new ShellFactoryImpl(shellParams -> {
LineReader reader = LineReaderBuilder.builder()
.terminal(shellParams.getTerminal())
.build();

try {
String line;
reader.printAbove("Welcome to SSH Server");
while ((line = reader.readLine("sshTest > ")) != null) {
System.out.println(line);
}
} catch (UserInterruptException e) {
// Ignore
} catch (EndOfFileException e) {
// Ignore
} catch (Exception e) {
// ignore OTHER EXCEPTIONS
}
}));

// Start the server
sshd.start();
System.out.println("SSH Server started on port 2222");

SshClient client = SshClient.setUpDefaultClient();
client.start();
ClientSession session =
client.connect("test", "localhost", sshd.getPort()).verify().getClientSession();
session.addPasswordIdentity("foo");
session.auth().verify();
ChannelShell shell = session.createShellChannel();
shell.open().verify();
shell.getInvertedIn().write("echo foo\n".getBytes());
shell.close();
client.close();

Thread.sleep(1000);
}
}