aboutsummaryrefslogtreecommitdiffstats
path: root/src/org
diff options
context:
space:
mode:
authorKenny Root <kenny@the-b.org>2009-06-02 01:20:39 +0000
committerKenny Root <kenny@the-b.org>2009-06-02 01:20:39 +0000
commit0b1f5e775236a489efa28f7c2b8ebecd7c05e758 (patch)
tree0ca456e6fcaeb1a045122c4fcc70a0f816f813d2 /src/org
parent3bfe899377534203ff3ee3c06c515733b74b78d9 (diff)
downloadconnectbot-0b1f5e775236a489efa28f7c2b8ebecd7c05e758.tar.gz
connectbot-0b1f5e775236a489efa28f7c2b8ebecd7c05e758.tar.bz2
connectbot-0b1f5e775236a489efa28f7c2b8ebecd7c05e758.zip
Refactor relay into separate class
git-svn-id: https://connectbot.googlecode.com/svn/trunk/connectbot@257 df292f66-193f-0410-a5fc-6d59da041ff2
Diffstat (limited to 'src/org')
-rw-r--r--src/org/connectbot/service/Relay.java218
-rw-r--r--src/org/connectbot/service/TerminalBridge.java156
2 files changed, 223 insertions, 151 deletions
diff --git a/src/org/connectbot/service/Relay.java b/src/org/connectbot/service/Relay.java
new file mode 100644
index 0000000..f713210
--- /dev/null
+++ b/src/org/connectbot/service/Relay.java
@@ -0,0 +1,218 @@
+/*
+ ConnectBot: simple, powerful, open-source SSH client for Android
+ Copyright (C) 2007-2008 Kenny Root, Jeffrey Sharkey
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+package org.connectbot.service;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+
+import android.util.Log;
+
+import com.trilead.ssh2.ChannelCondition;
+import com.trilead.ssh2.Session;
+
+import de.mud.terminal.vt320;
+
+/**
+ * @author Kenny Root
+ */
+public class Relay implements Runnable {
+ private static final String TAG = "ConnectBot.Relay";
+
+ private static final int BUFFER_SIZE = 4096;
+
+ private static final int CONDITIONS =
+ ChannelCondition.STDOUT_DATA
+ | ChannelCondition.STDERR_DATA
+ | ChannelCondition.CLOSED
+ | ChannelCondition.EOF;
+
+ private TerminalBridge bridge;
+
+ private CharsetDecoder decoder;
+ private CharsetDecoder replacer;
+
+ private Session session;
+
+ private InputStream stdout;
+ private InputStream stderr;
+
+ private vt320 buffer;
+
+ private ByteBuffer byteBuffer;
+ private CharBuffer charBuffer;
+
+ private byte[] byteArray;
+ private char[] charArray;
+
+ public Relay(TerminalBridge bridge, Session session, InputStream stdout, InputStream stderr, vt320 buffer, String encoding) {
+ setCharset(encoding);
+ this.bridge = bridge;
+ this.session = session;
+ this.stdout = stdout;
+ this.stderr = stderr;
+ this.buffer = buffer;
+ }
+
+ public void setCharset(String encoding) {
+ Charset charset = Charset.forName(encoding);
+
+ CharsetDecoder newCd = charset.newDecoder();
+ newCd.onUnmappableCharacter(CodingErrorAction.REPLACE);
+ newCd.onMalformedInput(CodingErrorAction.REPORT);
+
+ CharsetDecoder newReplacer = charset.newDecoder();
+ newReplacer.onUnmappableCharacter(CodingErrorAction.REPLACE);
+ newReplacer.onMalformedInput(CodingErrorAction.REPLACE);
+
+ decoder = newCd;
+ replacer = newReplacer;
+ }
+
+ public void run() {
+ byteBuffer = ByteBuffer.allocate(BUFFER_SIZE);
+ charBuffer = CharBuffer.allocate(BUFFER_SIZE);
+
+ byteArray = byteBuffer.array();
+ charArray = charBuffer.array();
+
+ int bytesRead = 0;
+ int offset = 0;
+
+ int newConditions = 0;
+
+ while((newConditions & ChannelCondition.CLOSED) == 0) {
+ try {
+ newConditions = session.waitForCondition(CONDITIONS, 0);
+ if ((newConditions & ChannelCondition.STDOUT_DATA) != 0) {
+ while (stdout.available() > 0) {
+ bytesRead = offset + stdout.read(byteArray, offset, BUFFER_SIZE - offset);
+
+ byteBuffer.position(0);
+ byteBuffer.limit(bytesRead);
+
+ CoderResult coderResult = decoder.decode(byteBuffer, charBuffer, true);
+
+ while (byteBuffer.position() < bytesRead) {
+ if (coderResult.isMalformed())
+ skipMalformedBytes(bytesRead, coderResult);
+
+ coderResult = decoder.decode(byteBuffer, charBuffer, true);
+ }
+
+ if (coderResult.isMalformed())
+ offset = discardMalformedBytes(bytesRead, coderResult);
+ else {
+ // No errors at all.
+ buffer.putString(charArray, 0, charBuffer.position());
+ offset = 0;
+ }
+
+ charBuffer.clear();
+ }
+
+ bridge.redraw();
+ }
+
+ if ((newConditions & ChannelCondition.STDERR_DATA) != 0)
+ logAndDiscard(stderr);
+
+ if ((newConditions & ChannelCondition.EOF) != 0) {
+ // The other side closed our channel, so let's disconnect.
+ // TODO review whether any tunnel is in use currently.
+ bridge.dispatchDisconnect(false);
+ break;
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Problem while handling incoming data in relay thread", e);
+ break;
+ }
+ }
+ }
+
+ /**
+ * @param stream
+\ * @throws IOException
+ */
+ private void logAndDiscard(InputStream stream) throws IOException {
+ while (stream.available() > 0) {
+ int n = stream.read(byteArray);
+ byteBuffer.position(0);
+ byteBuffer.limit(n);
+ replacer.decode(byteBuffer, charBuffer, false);
+ // TODO I don't know.. do we want this? We were ignoring it before
+ Log.d(TAG, String.format("Read data from stream: %s", new String(charArray, 0, charBuffer.position())));
+ charBuffer.clear();
+ }
+ }
+
+ /**
+ * @param n
+ * @param cr
+ * @return
+ */
+ private int discardMalformedBytes(int n, CoderResult cr) {
+ int offset;
+ /* If we still have malformed input, save the bytes for the next
+ * read and try to parse it again.
+ */
+ offset = n - byteBuffer.position() + cr.length();
+ System.arraycopy(byteArray, byteBuffer.position() - cr.length(), byteArray, 0, offset);
+ Log.d(TAG, String.format("Copying out %d chars at %d: 0x%02x",
+ offset, byteBuffer.position() - cr.length(),
+ byteArray[byteBuffer.position() - cr.length()]
+ ));
+ return offset;
+ }
+
+ /**
+ * @param numReadBytes
+ * @param errorResult
+ */
+ private void skipMalformedBytes(int numReadBytes, CoderResult errorResult) {
+ int curpos = byteBuffer.position() - errorResult.length();
+
+ if (curpos > 0) {
+ /* There is good data before the malformed section, so
+ * pass this on immediately.
+ */
+ buffer.putString(charArray, 0, charBuffer.position());
+ }
+
+ byteBuffer.position(curpos);
+ byteBuffer.limit(curpos + errorResult.length());
+
+ charBuffer.clear();
+ replacer.decode(byteBuffer, charBuffer, true);
+
+ buffer.putString(charArray, 0, charBuffer.position());
+
+ curpos += errorResult.length();
+
+ byteBuffer.position(curpos);
+ byteBuffer.limit(numReadBytes);
+
+ charBuffer.clear();
+ }
+}
diff --git a/src/org/connectbot/service/TerminalBridge.java b/src/org/connectbot/service/TerminalBridge.java
index 3cf0109..c12eeeb 100644
--- a/src/org/connectbot/service/TerminalBridge.java
+++ b/src/org/connectbot/service/TerminalBridge.java
@@ -21,12 +21,6 @@ package org.connectbot.service;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import java.nio.charset.Charset;
-import java.nio.charset.CharsetDecoder;
-import java.nio.charset.CoderResult;
-import java.nio.charset.CodingErrorAction;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
@@ -62,7 +56,6 @@ import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnKeyListener;
-import com.trilead.ssh2.ChannelCondition;
import com.trilead.ssh2.Connection;
import com.trilead.ssh2.ConnectionInfo;
import com.trilead.ssh2.ConnectionMonitor;
@@ -92,8 +85,6 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal
public final static String TAG = TerminalBridge.class.toString();
- private final static int BUFFER_SIZE = 4096;
-
public final static int DEFAULT_FONT_SIZE = 10;
public static final String AUTH_PUBLICKEY = "publickey",
@@ -123,7 +114,7 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal
private InputStream stderr;
- private Thread relay;
+ private Relay relay;
private final String emulation;
private final int scrollback;
@@ -195,144 +186,6 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal
protected ConnectionInfo connectionInfo;
- /**
- * @author kenny
- *
- */
- private final class Relay implements Runnable {
- final String encoding = host.getEncoding();
-
- public void run() {
- final Charset charset = Charset.forName(encoding);
-
- /* Set up character set decoder to report any byte sequences
- * which are malformed so we can try to resume decoding it
- * on the next packet received.
- *
- * UTF-8 byte sequences have a tendency to get truncated at
- * times.
- */
- final CharsetDecoder cd = charset.newDecoder();
- cd.onUnmappableCharacter(CodingErrorAction.REPLACE);
- cd.onMalformedInput(CodingErrorAction.REPORT);
-
- final CharsetDecoder replacer = charset.newDecoder();
- replacer.onUnmappableCharacter(CodingErrorAction.REPLACE);
- replacer.onMalformedInput(CodingErrorAction.REPLACE);
-
- ByteBuffer bb = ByteBuffer.allocate(BUFFER_SIZE);
- CharBuffer cb = CharBuffer.allocate(BUFFER_SIZE);
-
- final byte[] bba = bb.array();
- final char[] cba = cb.array();
- final byte[] tmpBuff = new byte[BUFFER_SIZE];
-
- int n = 0;
- int offset = 0;
-
- int conditions = ChannelCondition.STDOUT_DATA
- | ChannelCondition.STDERR_DATA
- | ChannelCondition.CLOSED
- | ChannelCondition.EOF;
- int newConditions = 0;
-
- while((newConditions & ChannelCondition.CLOSED) == 0) {
- try {
- newConditions = session.waitForCondition(conditions, 0);
- if ((newConditions & ChannelCondition.STDOUT_DATA) != 0) {
- while (stdout.available() > 0) {
- n = offset + stdout.read(bba, offset, BUFFER_SIZE - offset);
-
- bb.position(0);
- bb.limit(n);
-
- CoderResult cr = cd.decode(bb, cb, true);
-
- if (cr.isMalformed()) {
- int curpos = bb.position() - cr.length();
-
- if (curpos > 0) {
- /* There is good data before the malformed section, so
- * pass this on immediately.
- */
- ((vt320)buffer).putString(cba, 0, cb.position());
- }
-
- while (bb.position() < n) {
- bb.position(curpos);
- bb.limit(curpos + cr.length());
-
- cb.clear();
- replacer.decode(bb, cb, true);
-
- ((vt320) buffer).putString(cba, 0, cb.position());
-
- curpos += cr.length();
-
- bb.position(curpos);
- cb.limit(n);
-
- cb.clear();
- cr = cd.decode(bb, cb, true);
- }
-
- if (cr.isMalformed()) {
- /* If we still have malformed input, save the bytes for the next
- * read and try to parse it again.
- */
- offset = n - bb.position() + cr.length();
- if ((bb.position() - cr.length()) < offset) {
- System.arraycopy(bba, bb.position() - cr.length(), tmpBuff, 0, offset);
- System.arraycopy(tmpBuff, 0, bba, 0, offset);
- } else {
- System.arraycopy(bba, bb.position() - cr.length(), bba, 0, offset);
- }
- Log.d(TAG, String.format("Copying out %d chars at %d: 0x%02x",
- offset, bb.position() - cr.length(),
- bba[bb.position() - cr.length()]
- ));
- } else {
- // After discarding the previous offset, we only have valid data.
- ((vt320)buffer).putString(cba, 0, cb.position());
- offset = 0;
- }
- } else {
- // No errors at all.
- ((vt320)buffer).putString(cba, 0, cb.position());
- offset = 0;
- }
-
- cb.clear();
- }
- redraw();
- }
-
- if ((newConditions & ChannelCondition.STDERR_DATA) != 0) {
- while (stderr.available() > 0) {
- n = stderr.read(bba);
- bb.position(0);
- bb.limit(n);
- replacer.decode(bb, cb, false);
- // TODO I don't know.. do we want this? We were ignoring it before
- Log.d(TAG, String.format("Read data from stderr: %s", new String(cba, 0, cb.position())));
- cb.clear();
- }
- }
-
- if ((newConditions & ChannelCondition.EOF) != 0) {
- // The other side closed our channel, so let's disconnect.
- // TODO review whether any tunnel is in use currently.
- dispatchDisconnect(false);
- break;
- }
- } catch (IOException e) {
- Log.e(TAG, "Problem while handling incoming data in relay thread", e);
- break;
- }
- }
- }
- }
-
public class HostKeyVerifier implements ServerHostKeyVerifier {
public boolean verifyServerHostKey(String hostname, int port,
@@ -821,9 +674,10 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal
stderr = session.getStderr();
// create thread to relay incoming connection data to buffer
- relay = new Thread(new Relay());
- relay.setName("Relay");
- relay.start();
+ relay = new Relay(this, session, stdout, stderr, (vt320) buffer, host.getEncoding());
+ Thread relayThread = new Thread(relay);
+ relayThread.setName("Relay");
+ relayThread.start();
// force font-size to make sure we resizePTY as needed
setFontSize(fontSize);