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.Client; 8 import org.chromium.chromoting.jni.ConnectionListener; 9 import org.chromium.chromoting.jni.DirectoryService; 10 import org.chromium.chromoting.jni.DirectoryServiceRequestError; 11 12 /** 13 * This class manages making a connection to a host, with logic for reloading the host list and 14 * retrying the connection in the case of a stale host JID. 15 */ 16 public class SessionConnector implements ConnectionListener, DirectoryService.HostListCallback { 17 private Client mClient; 18 private ConnectionListener mConnectionListener; 19 private DirectoryService.HostListCallback mHostListCallback; 20 private DirectoryService mDirectoryService; 21 private SessionAuthenticator mAuthenticator; 22 23 private String mAccountName; 24 private String mAuthToken; 25 26 /* HostInfo for the host we are connecting to. */ 27 private HostInfo mHost; 28 29 private String mFlags; 30 31 /** 32 * Tracks whether the connection has been established. Auto-reloading and reconnecting should 33 * only happen if connection has not yet occurred. 34 */ 35 private boolean mWasConnected; 36 private boolean mTriedReloadingHostList; 37 38 /** 39 * @param connectionListener Object to be notified on connection success/failure. 40 * @param hostListCallback Object to be notified whenever the host list is reloaded. 41 * @param directoryService The object used for reloading the host list. 42 */ SessionConnector(Client client, ConnectionListener connectionListener, DirectoryService.HostListCallback hostListCallback, DirectoryService directoryService)43 public SessionConnector(Client client, ConnectionListener connectionListener, 44 DirectoryService.HostListCallback hostListCallback, DirectoryService directoryService) { 45 mClient = client; 46 mConnectionListener = connectionListener; 47 mHostListCallback = hostListCallback; 48 mDirectoryService = directoryService; 49 } 50 51 /** Initiates a connection to the host. */ connectToHost(String accountName, String authToken, HostInfo host, SessionAuthenticator authenticator, String flags)52 public void connectToHost(String accountName, String authToken, HostInfo host, 53 SessionAuthenticator authenticator, String flags) { 54 mAccountName = accountName; 55 mAuthToken = authToken; 56 mHost = host; 57 mAuthenticator = authenticator; 58 mFlags = flags; 59 60 if (host.isIncomplete()) { 61 // These keys might not be present in a newly-registered host, so treat this as a 62 // connection failure and reload the host list. 63 reloadHostListAndConnect(); 64 return; 65 } 66 67 doConnect(); 68 } 69 doConnect()70 private void doConnect() { 71 mClient.connectToHost(mAccountName, mAuthToken, mHost.jabberId, mHost.ftlId, mHost.id, 72 mHost.publicKey, mAuthenticator, mFlags, mHost.hostVersion, mHost.hostOs, 73 mHost.hostOsVersion, this); 74 } 75 reloadHostListAndConnect()76 private void reloadHostListAndConnect() { 77 mTriedReloadingHostList = true; 78 mDirectoryService.retrieveHostList(this); 79 } 80 81 @Override onConnectionState( @onnectionListener.State int state, @ConnectionListener.Error int error)82 public void onConnectionState( 83 @ConnectionListener.State int state, @ConnectionListener.Error int error) { 84 switch (state) { 85 case ConnectionListener.State.CONNECTED: 86 mWasConnected = true; 87 break; 88 case ConnectionListener.State.FAILED: 89 // The host is offline, which may mean the JID is out of date, so refresh the host 90 // list and try to connect again. 91 if (error == ConnectionListener.Error.PEER_IS_OFFLINE && !mWasConnected 92 && !mTriedReloadingHostList) { 93 reloadHostListAndConnect(); 94 return; 95 } 96 break; 97 default: 98 break; 99 } 100 101 // Pass the state/error back to the caller. 102 mConnectionListener.onConnectionState(state, error); 103 } 104 105 @Override onHostListReceived(HostInfo[] hosts)106 public void onHostListReceived(HostInfo[] hosts) { 107 // Notify the caller, so the UI is updated. 108 mHostListCallback.onHostListReceived(hosts); 109 110 HostInfo foundHost = null; 111 for (HostInfo host : hosts) { 112 if (host.id.equals(mHost.id)) { 113 foundHost = host; 114 break; 115 } 116 } 117 118 if (foundHost == null || foundHost.ftlId.equals(mHost.ftlId) || foundHost.isIncomplete()) { 119 // Cannot reconnect to this host, or there's no point in trying because the FtlId is 120 // unchanged, so report connection error to the client. 121 mConnectionListener.onConnectionState(ConnectionListener.State.FAILED, 122 ConnectionListener.Error.PEER_IS_OFFLINE); 123 } else { 124 mHost = foundHost; 125 doConnect(); 126 } 127 } 128 129 @Override onError(@irectoryServiceRequestError int error)130 public void onError(@DirectoryServiceRequestError int error) { 131 // Connection failed and reloading the host list also failed, so report the connection 132 // error. 133 mConnectionListener.onConnectionState(ConnectionListener.State.FAILED, 134 ConnectionListener.Error.PEER_IS_OFFLINE); 135 136 // Notify the caller that the host list failed to load, so the UI is updated accordingly. 137 // The currently-displayed host list is not likely to be valid any more. 138 mHostListCallback.onError(error); 139 } 140 } 141