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