Home | History | Annotate | Download | only in chromoting
      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