Skip to content

Commit

Permalink
[GCM] Add ConnectionListener support, and hook up to debug page
Browse files Browse the repository at this point in the history
The ConnectionFactory::ConnectionListener gets informed of connection events,
including the actual ip endpoint with which a connection was established. This
will eventually be hooked up to app handlers to allow services to act on
connection changes. For now it just allows the debug page to more accurately
reflect the connection state.

BUG=377882

Review URL: https://codereview.chromium.org/317723004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@276800 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
zea@chromium.org committed Jun 12, 2014
1 parent 0ec86f5 commit c31e1b5
Show file tree
Hide file tree
Showing 9 changed files with 151 additions and 5 deletions.
15 changes: 14 additions & 1 deletion components/gcm_driver/gcm_client_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ void GCMClientImpl::InitializeMCSClient(
network_session_,
net_log_.net_log(),
&recorder_);
connection_factory_->SetConnectionListener(this);
mcs_client_ = internals_builder_->BuildMCSClient(
chrome_build_info_.version,
clock_.get(),
Expand Down Expand Up @@ -711,8 +712,9 @@ GCMClient::GCMStatistics GCMClientImpl::GetStatistics() const {
stats.is_recording = recorder_.is_recording();
stats.gcm_client_state = GetStateString();
stats.connection_client_created = mcs_client_.get() != NULL;
if (connection_factory_.get())
stats.connection_state = connection_factory_->GetConnectionStateString();
if (mcs_client_.get()) {
stats.connection_state = mcs_client_->GetStateString();
stats.send_queue_size = mcs_client_->GetSendQueueSize();
stats.resend_queue_size = mcs_client_->GetResendQueueSize();
}
Expand All @@ -731,6 +733,17 @@ void GCMClientImpl::OnActivityRecorded() {
delegate_->OnActivityRecorded();
}

void GCMClientImpl::OnConnected(const GURL& current_server,
const net::IPEndPoint& ip_endpoint) {
// TODO(zea): inform GCMClient::Delegate and app handlers as well.
delegate_->OnActivityRecorded();
}

void GCMClientImpl::OnDisconnected() {
// TODO(zea): inform GCMClient::Delegate and app handlers as well.
delegate_->OnActivityRecorded();
}

void GCMClientImpl::OnMessageReceivedFromMCS(const gcm::MCSMessage& message) {
switch (message.tag()) {
case kLoginResponseTag:
Expand Down
12 changes: 10 additions & 2 deletions components/gcm_driver/gcm_client_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,13 @@ class GCMInternalsBuilder {
// Checkins. It also allows for registering user delegates that host
// applications that send and receive messages.
class GCMClientImpl
: public GCMClient, public GCMStatsRecorder::Delegate {
: public GCMClient, public GCMStatsRecorder::Delegate,
public ConnectionFactory::ConnectionListener {
public:
explicit GCMClientImpl(scoped_ptr<GCMInternalsBuilder> internals_builder);
virtual ~GCMClientImpl();

// Overridden from GCMClient:
// GCMClient implementation.
virtual void Initialize(
const ChromeBuildInfo& chrome_build_info,
const base::FilePath& store_path,
Expand All @@ -101,8 +102,15 @@ class GCMClientImpl
virtual void SetRecording(bool recording) OVERRIDE;
virtual void ClearActivityLogs() OVERRIDE;
virtual GCMStatistics GetStatistics() const OVERRIDE;

// GCMStatsRecorder::Delegate implemenation.
virtual void OnActivityRecorded() OVERRIDE;

// ConnectionFactory::ConnectionListener implementation.
virtual void OnConnected(const GURL& current_server,
const net::IPEndPoint& ip_endpoint) OVERRIDE;
virtual void OnDisconnected() OVERRIDE;

private:
// State representation of the GCMClient.
// Any change made to this enum should have corresponding change in the
Expand Down
3 changes: 3 additions & 0 deletions google_apis/gcm/engine/connection_factory.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

namespace gcm {

ConnectionFactory::ConnectionListener::ConnectionListener() {}
ConnectionFactory::ConnectionListener::~ConnectionListener() {}

ConnectionFactory::ConnectionFactory() {}
ConnectionFactory::~ConnectionFactory() {}

Expand Down
32 changes: 32 additions & 0 deletions google_apis/gcm/engine/connection_factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,18 @@
#ifndef GOOGLE_APIS_GCM_ENGINE_CONNECTION_FACTORY_H_
#define GOOGLE_APIS_GCM_ENGINE_CONNECTION_FACTORY_H_

#include <string>

#include "base/time/time.h"
#include "google_apis/gcm/base/gcm_export.h"
#include "google_apis/gcm/engine/connection_handler.h"

class GURL;

namespace net {
class IPEndPoint;
}

namespace mcs_proto {
class LoginRequest;
}
Expand Down Expand Up @@ -36,6 +44,22 @@ class GCM_EXPORT ConnectionFactory {
CONNECTION_RESET_COUNT,
};

// Listener interface to be notified of endpoint connection events.
class GCM_EXPORT ConnectionListener {
public:
ConnectionListener();
virtual ~ConnectionListener();

// Notifies the listener that GCM has performed a handshake with and is now
// actively connected to |current_server|. |ip_endpoint| is the resolved
// ip address/port through which the connection is being made.
virtual void OnConnected(const GURL& current_server,
const net::IPEndPoint& ip_endpoint) = 0;

// Notifies the listener that the connection has been interrupted.
virtual void OnDisconnected() = 0;
};

ConnectionFactory();
virtual ~ConnectionFactory();

Expand Down Expand Up @@ -66,6 +90,9 @@ class GCM_EXPORT ConnectionFactory {
// connection.
virtual bool IsEndpointReachable() const = 0;

// Returns a debug string describing the connection state.
virtual std::string GetConnectionStateString() const = 0;

// If in backoff, the time at which the next retry will be made. Otherwise,
// a null time, indicating either no attempt to connect has been made or no
// backoff is in progress.
Expand All @@ -76,6 +103,11 @@ class GCM_EXPORT ConnectionFactory {
// If the last connection was made within kConnectionResetWindowSecs, the old
// backoff is restored, else a new backoff kicks off.
virtual void SignalConnectionReset(ConnectionResetReason reason) = 0;

// Sets the current connection listener. Only one listener is supported at a
// time, and the listener must either outlive the connection factory or
// call SetConnectionListener(NULL) upon destruction.
virtual void SetConnectionListener(ConnectionListener* listener) = 0;
};

} // namespace gcm
Expand Down
36 changes: 36 additions & 0 deletions google_apis/gcm/engine/connection_factory_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ ConnectionFactoryImpl::ConnectionFactoryImpl(
waiting_for_backoff_(false),
logging_in_(false),
recorder_(recorder),
listener_(NULL),
weak_ptr_factory_(this) {
DCHECK_GE(mcs_endpoints_.size(), 1U);
}
Expand Down Expand Up @@ -140,6 +141,18 @@ bool ConnectionFactoryImpl::IsEndpointReachable() const {
return connection_handler_ && connection_handler_->CanSendMessage();
}

std::string ConnectionFactoryImpl::GetConnectionStateString() const {
if (IsEndpointReachable())
return "CONNECTED";
if (logging_in_)
return "LOGGING IN";
if (connecting_)
return "CONNECTING";
if (waiting_for_backoff_)
return "WAITING FOR BACKOFF";
return "NOT CONNECTED";
}

void ConnectionFactoryImpl::SignalConnectionReset(
ConnectionResetReason reason) {
// A failure can trigger multiple resets, so no need to do anything if a
Expand All @@ -149,6 +162,9 @@ void ConnectionFactoryImpl::SignalConnectionReset(
return;
}

if (listener_)
listener_->OnDisconnected();

UMA_HISTOGRAM_ENUMERATION("GCM.ConnectionResetReason",
reason,
CONNECTION_RESET_COUNT);
Expand Down Expand Up @@ -202,6 +218,11 @@ void ConnectionFactoryImpl::SignalConnectionReset(
Connect();
}

void ConnectionFactoryImpl::SetConnectionListener(
ConnectionListener* listener) {
listener_ = listener;
}

base::TimeTicks ConnectionFactoryImpl::NextRetryAttempt() const {
if (!backoff_entry_)
return base::TimeTicks();
Expand Down Expand Up @@ -234,6 +255,18 @@ GURL ConnectionFactoryImpl::GetCurrentEndpoint() const {
return mcs_endpoints_[next_endpoint_];
}

net::IPEndPoint ConnectionFactoryImpl::GetPeerIP() {
if (!socket_handle_.socket())
return net::IPEndPoint();

net::IPEndPoint ip_endpoint;
int result = socket_handle_.socket()->GetPeerAddress(&ip_endpoint);
if (result != net::OK)
return net::IPEndPoint();

return ip_endpoint;
}

void ConnectionFactoryImpl::ConnectImpl() {
DCHECK(!IsEndpointReachable());
DCHECK(!socket_handle_.socket());
Expand Down Expand Up @@ -348,6 +381,9 @@ void ConnectionFactoryImpl::ConnectionHandlerCallback(int result) {
previous_backoff_.swap(backoff_entry_);
backoff_entry_->Reset();
logging_in_ = false;

if (listener_)
listener_->OnConnected(GetCurrentEndpoint(), GetPeerIP());
}

// This has largely been copied from
Expand Down
9 changes: 9 additions & 0 deletions google_apis/gcm/engine/connection_factory_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,10 @@ class GCM_EXPORT ConnectionFactoryImpl :
virtual ConnectionHandler* GetConnectionHandler() const OVERRIDE;
virtual void Connect() OVERRIDE;
virtual bool IsEndpointReachable() const OVERRIDE;
virtual std::string GetConnectionStateString() const OVERRIDE;
virtual base::TimeTicks NextRetryAttempt() const OVERRIDE;
virtual void SignalConnectionReset(ConnectionResetReason reason) OVERRIDE;
virtual void SetConnectionListener(ConnectionListener* listener) OVERRIDE;

// NetworkChangeNotifier observer implementations.
virtual void OnConnectionTypeChanged(
Expand All @@ -61,6 +63,10 @@ class GCM_EXPORT ConnectionFactoryImpl :
// attempt will be made.
GURL GetCurrentEndpoint() const;

// Returns the IPEndpoint to which the factory is currently connected. If no
// connection is active, returns an empty IPEndpoint.
net::IPEndPoint GetPeerIP();

protected:
// Implementation of Connect(..). If not in backoff, uses |login_request_|
// in attempting a connection/handshake. On connection/handshake failure, goes
Expand Down Expand Up @@ -161,6 +167,9 @@ class GCM_EXPORT ConnectionFactoryImpl :
// Recorder that records GCM activities for debugging purpose. Not owned.
GCMStatsRecorder* recorder_;

// Listener for connection change events.
ConnectionListener* listener_;

base::WeakPtrFactory<ConnectionFactoryImpl> weak_ptr_factory_;

DISALLOW_COPY_AND_ASSIGN(ConnectionFactoryImpl);
Expand Down
Loading

0 comments on commit c31e1b5

Please sign in to comment.