blob: fc965fb7c99d0c2022b341772374241e2130df0c [file] [log] [blame]
// Copyright 2013 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.
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "google_apis/gcm/engine/connection_handler.h"
namespace mcs_proto {
class LoginRequest;
} // namespace mcs_proto
namespace gcm {
class GCM_EXPORT ConnectionHandlerImpl : public ConnectionHandler {
// |read_callback| will be invoked with the contents of any received protobuf
// message.
// |write_callback| will be invoked anytime a message has been successfully
// sent. Note: this just means the data was sent to the wire, not that the
// other end received it.
// |connection_callback| will be invoked with any fatal read/write errors
// encountered.
base::TimeDelta read_timeout,
const ProtoReceivedCallback& read_callback,
const ProtoSentCallback& write_callback,
const ConnectionChangedCallback& connection_callback);
~ConnectionHandlerImpl() override;
// ConnectionHandler implementation.
void Init(const mcs_proto::LoginRequest& login_request,
net::StreamSocket* socket) override;
void Reset() override;
bool CanSendMessage() const override;
void SendMessage(const google::protobuf::MessageLite& message) override;
// State machine for handling incoming data. See WaitForData(..) for usage.
enum ProcessingState {
// Processing the version, tag, and size packets (assuming minimum length
// size packet). Only used during the login handshake.
// Processing the tag and size packets (assuming minimum length size
// packet). Used for normal messages.
// Processing a maximum length size packet (for messages with length > 128).
// Used when a normal size packet was not sufficient to read the message
// size.
// Processing the protocol buffer bytes (for those messages with non-zero
// sizes).
// Sends the protocol version and login request. First step in the MCS
// connection handshake.
void Login(const google::protobuf::MessageLite& login_request);
// SendMessage continuation. Invoked when Socket::Write completes.
void OnMessageSent();
// Starts the message processing process, which is comprised of the tag,
// message size, and bytes packet types.
void GetNextMessage();
// Performs any necessary SocketInputStream refreshing until the data
// associated with |packet_type| is fully ready, then calls the appropriate
// OnGot* message to process the packet data. If the read times out,
// will close the stream and invoke the connection callback.
void WaitForData(ProcessingState state);
// Incoming data helper methods.
void OnGotVersion();
void OnGotMessageTag();
void OnGotMessageSize();
void OnGotMessageBytes();
// Timeout handler.
void OnTimeout();
// Closes the current connection.
void CloseConnection();
// Timeout policy: the timeout is only enforced while waiting on the
// handshake (version and/or LoginResponse) or once at least a tag packet has
// been received. It is reset every time new data is received, and is
// only stopped when a full message is processed.
// TODO(zea): consider enforcing a separate timeout when waiting for
// a message to send.
const base::TimeDelta read_timeout_;
base::OneShotTimer<ConnectionHandlerImpl> read_timeout_timer_;
// This connection's socket and the input/output streams attached to it.
net::StreamSocket* socket_;
scoped_ptr<SocketInputStream> input_stream_;
scoped_ptr<SocketOutputStream> output_stream_;
// Whether the MCS login handshake has successfully completed. See Init(..)
// description for more info on what the handshake involves.
bool handshake_complete_;
// State for the message currently being processed, if there is one.
uint8 message_tag_;
uint32 message_size_;
ProtoReceivedCallback read_callback_;
ProtoSentCallback write_callback_;
ConnectionChangedCallback connection_callback_;
base::WeakPtrFactory<ConnectionHandlerImpl> weak_ptr_factory_;
} // namespace gcm