summaryrefslogtreecommitdiffstats
path: root/remoting/android/java/src/org/chromium/chromoting/SessionConnector.java
blob: 4fa95229a7825e64217707f1d10c3fbfbbab5c9c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.chromoting;

import org.chromium.chromoting.jni.ConnectionListener;
import org.chromium.chromoting.jni.JniInterface;

/**
 * This class manages making a connection to a host, with logic for reloading the host list and
 * retrying the connection in the case of a stale host JID.
 */
public class SessionConnector implements ConnectionListener,
        HostListLoader.Callback {
    private ConnectionListener mConnectionListener;
    private HostListLoader.Callback mHostListCallback;
    private HostListLoader mHostListLoader;
    private SessionAuthenticator mAuthenticator;

    private String mAccountName;
    private String mAuthToken;

    /* HostInfo for the host we are connecting to. */
    private HostInfo mHost;

    private String mFlags;

    /**
     * Tracks whether the connection has been established. Auto-reloading and reconnecting should
     * only happen if connection has not yet occurred.
     */
    private boolean mWasConnected;
    private boolean mTriedReloadingHostList;

    /**
     * @param connectionListener Object to be notified on connection success/failure.
     * @param hostListCallback Object to be notified whenever the host list is reloaded.
     * @param hostListLoader The object used for reloading the host list.
     */
    public SessionConnector(ConnectionListener connectionListener,
            HostListLoader.Callback hostListCallback, HostListLoader hostListLoader) {
        mConnectionListener = connectionListener;
        mHostListCallback = hostListCallback;
        mHostListLoader = hostListLoader;
    }

    /** Initiates a connection to the host. */
    public void connectToHost(String accountName, String authToken, HostInfo host,
            SessionAuthenticator authenticator, String flags) {
        mAccountName = accountName;
        mAuthToken = authToken;
        mHost = host;
        mAuthenticator = authenticator;
        mFlags = flags;

        if (hostIncomplete(host)) {
            // These keys might not be present in a newly-registered host, so treat this as a
            // connection failure and reload the host list.
            reloadHostListAndConnect();
            return;
        }

        doConnect();
    }

    private void doConnect() {
        JniInterface.connectToHost(mAccountName, mAuthToken, mHost.jabberId, mHost.id,
                mHost.publicKey, mAuthenticator, mFlags, this);
    }

    private static boolean hostIncomplete(HostInfo host) {
        return host.jabberId.isEmpty() || host.publicKey.isEmpty();
    }

    private void reloadHostListAndConnect() {
        mTriedReloadingHostList = true;
        mHostListLoader.retrieveHostList(mAuthToken, this);
    }

    @Override
    public void onConnectionState(ConnectionListener.State state, ConnectionListener.Error error) {
        switch (state) {
            case CONNECTED:
                mWasConnected = true;
                break;
            case FAILED:
                // The host is offline, which may mean the JID is out of date, so refresh the host
                // list and try to connect again.
                if (error == ConnectionListener.Error.PEER_IS_OFFLINE && !mWasConnected
                        && !mTriedReloadingHostList) {
                    reloadHostListAndConnect();
                    return;
                }
                break;
        }

         // Pass the state/error back to the caller.
        mConnectionListener.onConnectionState(state, error);
    }

    @Override
    public void onHostListReceived(HostInfo[] hosts) {
        // Notify the caller, so the UI is updated.
        mHostListCallback.onHostListReceived(hosts);

        HostInfo foundHost = null;
        for (HostInfo host : hosts) {
            if (host.id.equals(mHost.id)) {
                foundHost = host;
                break;
            }
        }

        if (foundHost == null || foundHost.jabberId.equals(mHost.jabberId)
                || hostIncomplete(foundHost)) {
            // Cannot reconnect to this host, or there's no point in trying because the JID is
            // unchanged, so report connection error to the client.
            mConnectionListener.onConnectionState(ConnectionListener.State.FAILED,
                    ConnectionListener.Error.PEER_IS_OFFLINE);
        } else {
            mHost = foundHost;
            doConnect();
        }
    }

    @Override
    public void onError(HostListLoader.Error error) {
        // Connection failed and reloading the host list also failed, so report the connection
        // error.
        mConnectionListener.onConnectionState(ConnectionListener.State.FAILED,
                ConnectionListener.Error.PEER_IS_OFFLINE);

        // Notify the caller that the host list failed to load, so the UI is updated accordingly.
        // The currently-displayed host list is not likely to be valid any more.
        mHostListCallback.onError(error);
    }
}