aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKenny Root <kenny@the-b.org>2010-03-08 05:47:40 +0000
committerKenny Root <kenny@the-b.org>2010-03-08 05:47:40 +0000
commit6282d0ac998d3e0ca4c909a4774f974a6af103e2 (patch)
tree21653c5965374bc74bf11f02ece8b078008879e4 /src
parentf9fa28bcdd82385a1f1bf6d8e908582303e455a2 (diff)
downloadconnectbot-6282d0ac998d3e0ca4c909a4774f974a6af103e2.tar.gz
connectbot-6282d0ac998d3e0ca4c909a4774f974a6af103e2.tar.bz2
connectbot-6282d0ac998d3e0ca4c909a4774f974a6af103e2.zip
First pass at fixing auto-reconnect
Queue up reconnections until we receive notifications from the system that we're connected again. Need to hook up a better user notification system for network connectivity problems. git-svn-id: https://connectbot.googlecode.com/svn/trunk/connectbot@486 df292f66-193f-0410-a5fc-6d59da041ff2
Diffstat (limited to 'src')
-rw-r--r--src/org/connectbot/ConsoleActivity.java10
-rw-r--r--src/org/connectbot/HostEditorActivity.java8
-rw-r--r--src/org/connectbot/HostListActivity.java4
-rw-r--r--src/org/connectbot/PortForwardListActivity.java12
-rw-r--r--src/org/connectbot/service/TerminalBridge.java13
-rw-r--r--src/org/connectbot/service/TerminalManager.java202
-rw-r--r--src/org/connectbot/transport/AbsTransport.java5
-rw-r--r--src/org/connectbot/transport/Local.java8
-rw-r--r--src/org/connectbot/transport/SSH.java8
-rw-r--r--src/org/connectbot/transport/Telnet.java8
10 files changed, 195 insertions, 83 deletions
diff --git a/src/org/connectbot/ConsoleActivity.java b/src/org/connectbot/ConsoleActivity.java
index b0c9e83..234ef43 100644
--- a/src/org/connectbot/ConsoleActivity.java
+++ b/src/org/connectbot/ConsoleActivity.java
@@ -149,7 +149,7 @@ public class ConsoleActivity extends Activity {
final String requestedNickname = (requested != null) ? requested.getFragment() : null;
int requestedIndex = 0;
- TerminalBridge requestedBridge = bound.getBridgeByName(requestedNickname);
+ TerminalBridge requestedBridge = bound.getConnectedBridge(requestedNickname);
// If we didn't find the requested connection, try opening it
if (requestedNickname != null && requestedBridge == null) {
@@ -176,8 +176,10 @@ public class ConsoleActivity extends Activity {
public void onServiceDisconnected(ComponentName className) {
// tell each bridge to forget about our prompt handler
- for(TerminalBridge bridge : bound.bridges)
- bridge.promptHelper.setHandler(null);
+ synchronized (bound.bridges) {
+ for(TerminalBridge bridge : bound.bridges)
+ bridge.promptHelper.setHandler(null);
+ }
flip.removeAllViews();
updateEmptyVisible();
@@ -852,7 +854,7 @@ public class ConsoleActivity extends Activity {
return;
}
- TerminalBridge requestedBridge = bound.getBridgeByName(requested.getFragment());
+ TerminalBridge requestedBridge = bound.getConnectedBridge(requested.getFragment());
int requestedIndex = 0;
synchronized (flip) {
diff --git a/src/org/connectbot/HostEditorActivity.java b/src/org/connectbot/HostEditorActivity.java
index e8202e2..95d04cc 100644
--- a/src/org/connectbot/HostEditorActivity.java
+++ b/src/org/connectbot/HostEditorActivity.java
@@ -240,13 +240,7 @@ public class HostEditorActivity extends PreferenceActivity implements OnSharedPr
public void onServiceConnected(ComponentName className, IBinder service) {
TerminalManager bound = ((TerminalManager.TerminalBinder) service).getService();
- for (TerminalBridge bridge: bound.bridges) {
- if (bridge.host.equals(host)) {
- hostBridge = bridge;
- Log.d(TAG, "Found host bridge; charset updates will be made live");
- break;
- }
- }
+ hostBridge = bound.getConnectedBridge(host);
}
public void onServiceDisconnected(ComponentName name) {
diff --git a/src/org/connectbot/HostListActivity.java b/src/org/connectbot/HostListActivity.java
index c477a58..94cc1ad 100644
--- a/src/org/connectbot/HostListActivity.java
+++ b/src/org/connectbot/HostListActivity.java
@@ -330,7 +330,7 @@ public class HostListActivity extends ListActivity {
// edit, disconnect, delete
MenuItem connect = menu.add(R.string.list_host_disconnect);
- final TerminalBridge bridge = bound.findBridge(host);
+ final TerminalBridge bridge = bound.getConnectedBridge(host);
connect.setEnabled((bridge != null));
connect.setOnMenuItemClickListener(new OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
@@ -473,7 +473,7 @@ public class HostListActivity extends ListActivity {
if (this.manager == null)
return STATE_UNKNOWN;
- if (manager.findBridge(host) != null)
+ if (manager.getConnectedBridge(host) != null)
return STATE_CONNECTED;
if (manager.disconnected.contains(host))
diff --git a/src/org/connectbot/PortForwardListActivity.java b/src/org/connectbot/PortForwardListActivity.java
index 2cb5dbc..137030a 100644
--- a/src/org/connectbot/PortForwardListActivity.java
+++ b/src/org/connectbot/PortForwardListActivity.java
@@ -132,16 +132,8 @@ public class PortForwardListActivity extends ListActivity {
public void onServiceConnected(ComponentName className, IBinder service) {
TerminalManager bound = ((TerminalManager.TerminalBinder) service).getService();
- for (TerminalBridge bridge: bound.bridges) {
- if (bridge.host.equals(host)) {
- hostBridge = bridge;
- updateHandler.sendEmptyMessage(-1);
- Log.d(TAG, "Found host bridge; using that instead of database");
- break;
- }
- }
-
-
+ hostBridge = bound.getConnectedBridge(host);
+ updateHandler.sendEmptyMessage(-1);
}
public void onServiceDisconnected(ComponentName name) {
diff --git a/src/org/connectbot/service/TerminalBridge.java b/src/org/connectbot/service/TerminalBridge.java
index c748046..9a2a946 100644
--- a/src/org/connectbot/service/TerminalBridge.java
+++ b/src/org/connectbot/service/TerminalBridge.java
@@ -455,8 +455,12 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener {
if (disconnectListener != null)
disconnectListener.onDisconnected(TerminalBridge.this);
} else {
+ {
+ final String line = manager.res.getString(R.string.alert_disconnect_msg);
+ ((vt320) buffer).putString("\r\n" + line + "\r\n");
+ }
if (host.getStayConnected()) {
- startConnection();
+ manager.requestReconnect(this);
return;
}
Thread disconnectPromptThread = new Thread(new Runnable() {
@@ -1348,4 +1352,11 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener {
return urls;
}
+
+ /**
+ * @return
+ */
+ public boolean isUsingNetwork() {
+ return transport.usesNetwork();
+ }
}
diff --git a/src/org/connectbot/service/TerminalManager.java b/src/org/connectbot/service/TerminalManager.java
index 083969d..1b7b91d 100644
--- a/src/org/connectbot/service/TerminalManager.java
+++ b/src/org/connectbot/service/TerminalManager.java
@@ -18,6 +18,7 @@
package org.connectbot.service;
import java.io.IOException;
+import java.lang.ref.WeakReference;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Arrays;
@@ -48,10 +49,7 @@ import android.content.res.Resources;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
import android.net.Uri;
-import android.net.wifi.WifiManager;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -73,6 +71,11 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen
public final static String TAG = "ConnectBot.TerminalManager";
public List<TerminalBridge> bridges = new LinkedList<TerminalBridge>();
+ public Map<HostBean, WeakReference<TerminalBridge>> mHostBridgeMap =
+ new HashMap<HostBean, WeakReference<TerminalBridge>>();
+ public Map<String, WeakReference<TerminalBridge>> mNicknameBridgeMap =
+ new HashMap<String, WeakReference<TerminalBridge>>();
+
public TerminalBridge defaultBridge = null;
public List<HostBean> disconnected = new LinkedList<HostBean>();
@@ -88,10 +91,9 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen
protected SharedPreferences prefs;
- private final IBinder binder = new TerminalBinder();
+ final private IBinder binder = new TerminalBinder();
- private ConnectivityManager connectivityManager;
- private WifiManager.WifiLock wifilock;
+ private ConnectivityReceiver connectivityManager;
private MediaPlayer mediaPlayer;
@@ -108,6 +110,9 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen
private boolean resizeAllowed = true;
+ protected List<WeakReference<TerminalBridge>> mPendingReconnect
+ = new LinkedList<WeakReference<TerminalBridge>>();
+
@Override
public void onCreate() {
Log.i(TAG, "Starting background service");
@@ -139,29 +144,22 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen
}
}
- connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
-
- WifiManager manager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
- wifilock = manager.createWifiLock(TAG);
-
vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
wantKeyVibration = prefs.getBoolean(PreferenceConstants.BUMPY_ARROWS, true);
wantBellVibration = prefs.getBoolean(PreferenceConstants.BELL_VIBRATE, true);
enableMediaPlayer();
+
+ final boolean lockingWifi = prefs.getBoolean(PreferenceConstants.WIFI_LOCK, true);
+
+ connectivityManager = new ConnectivityReceiver(this, lockingWifi);
}
@Override
public void onDestroy() {
Log.i(TAG, "Destroying background service");
- if (bridges.size() > 0) {
- TerminalBridge[] tmpBridges = bridges.toArray(new TerminalBridge[bridges.size()]);
-
- // disconnect and dispose of any existing bridges
- for (int i = 0; i < tmpBridges.length; i++)
- tmpBridges[i].dispatchDisconnect(true);
- }
+ disconnectAll(true);
if(hostdb != null) {
hostdb.close();
@@ -180,8 +178,7 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen
pubkeyTimer.cancel();
}
- if (wifilock != null && wifilock.isHeld())
- wifilock.release();
+ connectivityManager.cleanup();
ConnectionNotifier.getInstance().hideRunningNotification(this);
@@ -189,26 +186,50 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen
}
/**
+ * Disconnect all currently connected bridges.
+ */
+ private void disconnectAll(final boolean immediate) {
+ TerminalBridge[] tmpBridges = null;
+
+ synchronized (bridges) {
+ if (bridges.size() > 0) {
+ tmpBridges = bridges.toArray(new TerminalBridge[bridges.size()]);
+ }
+ }
+
+ if (tmpBridges != null) {
+ // disconnect and dispose of any existing bridges
+ for (int i = 0; i < tmpBridges.length; i++)
+ tmpBridges[i].dispatchDisconnect(immediate);
+ }
+ }
+
+ /**
* Open a new SSH session using the given parameters.
*/
private TerminalBridge openConnection(HostBean host) throws IllegalArgumentException, IOException {
// throw exception if terminal already open
- if (findBridge(host) != null) {
+ if (getConnectedBridge(host) != null) {
throw new IllegalArgumentException("Connection already open for that nickname");
}
TerminalBridge bridge = new TerminalBridge(this, host);
bridge.setOnDisconnectedListener(this);
bridge.startConnection();
- bridges.add(bridge);
- // Add a reference to the WifiLock
- NetworkInfo info = connectivityManager.getActiveNetworkInfo();
- if (isLockingWifi() &&
- info != null &&
- info.getType() == ConnectivityManager.TYPE_WIFI) {
- Log.d(TAG, "Acquiring WifiLock");
- wifilock.acquire();
+ synchronized (bridges) {
+ bridges.add(bridge);
+ WeakReference<TerminalBridge> wr = new WeakReference<TerminalBridge>(bridge);
+ mHostBridgeMap.put(bridge.host, wr);
+ mNicknameBridgeMap.put(bridge.host.getNickname(), wr);
+ }
+
+ synchronized (disconnected) {
+ disconnected.remove(bridge.host);
+ }
+
+ if (bridge.isUsingNetwork()) {
+ connectivityManager.incRef();
}
// also update database with new connected time
@@ -238,10 +259,6 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen
return prefs.getString(PreferenceConstants.KEYMODE, PreferenceConstants.KEYMODE_RIGHT); // "Use right-side keys"
}
- public boolean isLockingWifi() {
- return prefs.getBoolean(PreferenceConstants.WIFI_LOCK, true);
- }
-
/**
* Open a new connection by reading parameters from the given URI. Follows
* format specified by an individual transport.
@@ -264,30 +281,57 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen
}
/**
- * Find the {@link TerminalBridge} with the given nickname.
+ * Find a connected {@link TerminalBridge} with the given HostBean.
+ *
+ * @param host the HostBean to search for
+ * @return TerminalBridge that uses the HostBean
*/
- public TerminalBridge findBridge(HostBean host) {
- // find the first active bridge with given nickname
- for(TerminalBridge bridge : bridges) {
- if (bridge.host.equals(host))
- return bridge;
+ public TerminalBridge getConnectedBridge(HostBean host) {
+ WeakReference<TerminalBridge> wr = mHostBridgeMap.get(host);
+ if (wr != null) {
+ return wr.get();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Find a connected {@link TerminalBridge} using its nickname.
+ *
+ * @param nickname
+ * @return TerminalBridge that matches nickname
+ */
+ public TerminalBridge getConnectedBridge(final String nickname) {
+ if (nickname == null) {
+ return null;
+ }
+ WeakReference<TerminalBridge> wr = mNicknameBridgeMap.get(nickname);
+ if (wr != null) {
+ return wr.get();
+ } else {
+ return null;
}
- return null;
}
/**
* Called by child bridge when somehow it's been disconnected.
*/
public void onDisconnected(TerminalBridge bridge) {
- // remove this bridge from our list
- bridges.remove(bridge);
+ synchronized (bridges) {
+ // remove this bridge from our list
+ bridges.remove(bridge);
- if (bridges.size() == 0 && wifilock.isHeld()) {
- Log.d(TAG, "WifiLock was held, releasing");
- wifilock.release();
+ mHostBridgeMap.remove(bridge.host);
+ mNicknameBridgeMap.remove(bridge.host.getNickname());
+
+ if (bridge.isUsingNetwork()) {
+ connectivityManager.decRef();
+ }
}
- disconnected.add(bridge.host);
+ synchronized (disconnected) {
+ disconnected.add(bridge.host);
+ }
// pass notification back up to gui
if (disconnectHandler != null)
@@ -557,6 +601,9 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen
} else if (PreferenceConstants.BUMPY_ARROWS.equals(key)) {
wantKeyVibration = sharedPreferences.getBoolean(
PreferenceConstants.BUMPY_ARROWS, true);
+ } else if (PreferenceConstants.WIFI_LOCK.equals(key)) {
+ final boolean lockingWifi = prefs.getBoolean(PreferenceConstants.WIFI_LOCK, true);
+ connectivityManager.setWantWifiLock(lockingWifi);
}
}
@@ -579,25 +626,62 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen
}
/**
- * @param requestedNickname
- * @return TerminalBridge that matches nickname.
+ * Called when connectivity to the network is lost and it doesn't appear
+ * we'll be getting a different connection any time soon.
*/
- public TerminalBridge getBridgeByName(final String requestedNickname) {
- if (requestedNickname == null) {
- return null;
- }
+ public void onConnectivityLost() {
+ final Thread t = new Thread() {
+ @Override
+ public void run() {
+ disconnectAll(false);
+ }
+ };
+ t.start();
+ }
- for (final TerminalBridge bridge : bridges) {
- final String nick = bridge.host.getNickname();
- if (nick == null) {
- continue;
+ /**
+ * Called when connectivity to the network is restored.
+ */
+ public void onConnectivityRestored() {
+ final Thread t = new Thread() {
+ @Override
+ public void run() {
+ reconnectPending();
}
+ };
+ t.start();
+ }
- if (nick.equals(requestedNickname)) {
- return bridge;
+ /**
+ * Insert request into reconnect queue to be executed either immediately
+ * or later when connectivity is restored depending on whether we're
+ * currently connected.
+ *
+ * @param bridge the TerminalBridge to reconnect when possible
+ */
+ public void requestReconnect(TerminalBridge bridge) {
+ synchronized (mPendingReconnect) {
+ mPendingReconnect.add(new WeakReference<TerminalBridge>(bridge));
+ if (connectivityManager.isConnected()) {
+ reconnectPending();
}
}
+ }
- return null;
+ /**
+ * Reconnect all bridges that were pending a reconnect when connectivity
+ * was lost.
+ */
+ private void reconnectPending() {
+ synchronized (mPendingReconnect) {
+ for (WeakReference<TerminalBridge> ref : mPendingReconnect) {
+ TerminalBridge bridge = ref.get();
+ if (bridge == null) {
+ continue;
+ }
+ bridge.startConnection();
+ }
+ mPendingReconnect.clear();
+ }
}
}
diff --git a/src/org/connectbot/transport/AbsTransport.java b/src/org/connectbot/transport/AbsTransport.java
index fbd4655..18397ea 100644
--- a/src/org/connectbot/transport/AbsTransport.java
+++ b/src/org/connectbot/transport/AbsTransport.java
@@ -246,4 +246,9 @@ public abstract class AbsTransport {
public static String getFormatHint(Context context) {
return "???";
}
+
+ /**
+ * @return
+ */
+ public abstract boolean usesNetwork();
}
diff --git a/src/org/connectbot/transport/Local.java b/src/org/connectbot/transport/Local.java
index 46903b2..5ace1b0 100644
--- a/src/org/connectbot/transport/Local.java
+++ b/src/org/connectbot/transport/Local.java
@@ -208,4 +208,12 @@ public class Local extends AbsTransport {
public static String getFormatHint(Context context) {
return context.getString(R.string.hostpref_nickname_title);
}
+
+ /* (non-Javadoc)
+ * @see org.connectbot.transport.AbsTransport#usesNetwork()
+ */
+ @Override
+ public boolean usesNetwork() {
+ return false;
+ }
}
diff --git a/src/org/connectbot/transport/SSH.java b/src/org/connectbot/transport/SSH.java
index 11e0659..7dfaf0c 100644
--- a/src/org/connectbot/transport/SSH.java
+++ b/src/org/connectbot/transport/SSH.java
@@ -944,4 +944,12 @@ public class SSH extends AbsTransport implements ConnectionMonitor, InteractiveC
agentLockPassphrase = lockPassphrase;
return true;
}
+
+ /* (non-Javadoc)
+ * @see org.connectbot.transport.AbsTransport#usesNetwork()
+ */
+ @Override
+ public boolean usesNetwork() {
+ return true;
+ }
}
diff --git a/src/org/connectbot/transport/Telnet.java b/src/org/connectbot/transport/Telnet.java
index b7388ad..5fde2f6 100644
--- a/src/org/connectbot/transport/Telnet.java
+++ b/src/org/connectbot/transport/Telnet.java
@@ -319,4 +319,12 @@ public class Telnet extends AbsTransport {
context.getString(R.string.format_hostname),
context.getString(R.string.format_port));
}
+
+ /* (non-Javadoc)
+ * @see org.connectbot.transport.AbsTransport#usesNetwork()
+ */
+ @Override
+ public boolean usesNetwork() {
+ return true;
+ }
}