1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.chromoting; 6 7 import org.chromium.chromoting.jni.JniInterface; 8 9 /** 10 * This class manages making a connection to a host, with logic for reloading the host list and 11 * retrying the connection in the case of a stale host JID. 12 */ 13 public class SessionConnector implements JniInterface.ConnectionListener, 14 HostListLoader.Callback { 15 private JniInterface.ConnectionListener mConnectionCallback; 16 private HostListLoader.Callback mHostListCallback; 17 private HostListLoader mHostListLoader; 18 19 private String mAccountName; 20 private String mAuthToken; 21 22 /** Used to find the HostInfo from the returned array after the host list is reloaded. */ 23 private String mHostId; 24 25 private String mHostJabberId; 26 27 /** 28 * @param connectionCallback Object to be notified on connection success/failure. 29 * @param hostListCallback Object to be notified whenever the host list is reloaded. 30 * @param hostListLoader The object used for reloading the host list. 31 */ 32 public SessionConnector(JniInterface.ConnectionListener connectionCallback, 33 HostListLoader.Callback hostListCallback, HostListLoader hostListLoader) { 34 mConnectionCallback = connectionCallback; 35 mHostListCallback = hostListCallback; 36 mHostListLoader = hostListLoader; 37 } 38 39 /** Initiates a connection to the host. */ 40 public void connectToHost(String accountName, String authToken, HostInfo host) { 41 mAccountName = accountName; 42 mAuthToken = authToken; 43 mHostId = host.id; 44 mHostJabberId = host.jabberId; 45 46 if (hostIncomplete(host)) { 47 // These keys might not be present in a newly-registered host, so treat this as a 48 // connection failure and reload the host list. 49 reloadHostListAndConnect(); 50 return; 51 } 52 53 JniInterface.connectToHost(accountName, authToken, host.jabberId, host.id, host.publicKey, 54 this); 55 } 56 57 private static boolean hostIncomplete(HostInfo host) { 58 return host.jabberId.isEmpty() || host.publicKey.isEmpty(); 59 } 60 61 private void reloadHostListAndConnect() { 62 mHostListLoader.retrieveHostList(mAuthToken, this); 63 } 64 65 @Override 66 public void onConnectionState(JniInterface.ConnectionListener.State state, 67 JniInterface.ConnectionListener.Error error) { 68 if (state == JniInterface.ConnectionListener.State.FAILED && 69 error == JniInterface.ConnectionListener.Error.PEER_IS_OFFLINE) { 70 // The host is offline, which may mean the JID is out of date, so refresh the host list 71 // and try to connect again. 72 reloadHostListAndConnect(); 73 } else { 74 // Pass the state/error back to the caller. 75 mConnectionCallback.onConnectionState(state, error); 76 } 77 } 78 79 @Override 80 public void onHostListReceived(HostInfo[] hosts) { 81 // Notify the caller, so the UI is updated. 82 mHostListCallback.onHostListReceived(hosts); 83 84 HostInfo foundHost = null; 85 for (HostInfo host : hosts) { 86 if (host.id.equals(mHostId)) { 87 foundHost = host; 88 break; 89 } 90 } 91 92 if (foundHost == null || foundHost.jabberId.equals(mHostJabberId) 93 || hostIncomplete(foundHost)) { 94 // Cannot reconnect to this host, or there's no point in trying because the JID is 95 // unchanged, so report the original failure to the client. 96 mConnectionCallback.onConnectionState(JniInterface.ConnectionListener.State.FAILED, 97 JniInterface.ConnectionListener.Error.PEER_IS_OFFLINE); 98 } else { 99 // Reconnect to the host, but use the original callback directly, instead of this 100 // wrapper object, so the host list is not loaded again. 101 JniInterface.connectToHost(mAccountName, mAuthToken, foundHost.jabberId, 102 foundHost.id, foundHost.publicKey, mConnectionCallback); 103 } 104 } 105 106 @Override 107 public void onError(HostListLoader.Error error) { 108 // Connection failed and reloading the host list also failed, so report the connection 109 // error. 110 mConnectionCallback.onConnectionState(JniInterface.ConnectionListener.State.FAILED, 111 JniInterface.ConnectionListener.Error.PEER_IS_OFFLINE); 112 113 // Notify the caller that the host list failed to load, so the UI is updated accordingly. 114 // The currently-displayed host list is not likely to be valid any more. 115 mHostListCallback.onError(error); 116 } 117 } 118