1// Copyright 2013 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#ifndef GOOGLE_APIS_GCM_ENGINE_CONNECTION_HANDLER_IMPL_H_
6#define GOOGLE_APIS_GCM_ENGINE_CONNECTION_HANDLER_IMPL_H_
7
8#include "base/memory/weak_ptr.h"
9#include "base/time/time.h"
10#include "base/timer/timer.h"
11#include "google_apis/gcm/engine/connection_handler.h"
12
13namespace mcs_proto {
14class LoginRequest;
15}  // namespace mcs_proto
16
17namespace gcm {
18
19class GCM_EXPORT ConnectionHandlerImpl : public ConnectionHandler {
20 public:
21  // |read_callback| will be invoked with the contents of any received protobuf
22  // message.
23  // |write_callback| will be invoked anytime a message has been successfully
24  // sent. Note: this just means the data was sent to the wire, not that the
25  // other end received it.
26  // |connection_callback| will be invoked with any fatal read/write errors
27  // encountered.
28  ConnectionHandlerImpl(
29      base::TimeDelta read_timeout,
30      const ProtoReceivedCallback& read_callback,
31      const ProtoSentCallback& write_callback,
32      const ConnectionChangedCallback& connection_callback);
33  virtual ~ConnectionHandlerImpl();
34
35  // ConnectionHandler implementation.
36  virtual void Init(const mcs_proto::LoginRequest& login_request,
37                    net::StreamSocket* socket) OVERRIDE;
38  virtual void Reset() OVERRIDE;
39  virtual bool CanSendMessage() const OVERRIDE;
40  virtual void SendMessage(const google::protobuf::MessageLite& message)
41      OVERRIDE;
42
43 private:
44  // State machine for handling incoming data. See WaitForData(..) for usage.
45  enum ProcessingState {
46    // Processing the version, tag, and size packets (assuming minimum length
47    // size packet). Only used during the login handshake.
48    MCS_VERSION_TAG_AND_SIZE = 0,
49    // Processing the tag and size packets (assuming minimum length size
50    // packet). Used for normal messages.
51    MCS_TAG_AND_SIZE,
52    // Processing a maximum length size packet (for messages with length > 128).
53    // Used when a normal size packet was not sufficient to read the message
54    // size.
55    MCS_FULL_SIZE,
56    // Processing the protocol buffer bytes (for those messages with non-zero
57    // sizes).
58    MCS_PROTO_BYTES
59  };
60
61  // Sends the protocol version and login request. First step in the MCS
62  // connection handshake.
63  void Login(const google::protobuf::MessageLite& login_request);
64
65  // SendMessage continuation. Invoked when Socket::Write completes.
66  void OnMessageSent();
67
68  // Starts the message processing process, which is comprised of the tag,
69  // message size, and bytes packet types.
70  void GetNextMessage();
71
72  // Performs any necessary SocketInputStream refreshing until the data
73  // associated with |packet_type| is fully ready, then calls the appropriate
74  // OnGot* message to process the packet data. If the read times out,
75  // will close the stream and invoke the connection callback.
76  void WaitForData(ProcessingState state);
77
78  // Incoming data helper methods.
79  void OnGotVersion();
80  void OnGotMessageTag();
81  void OnGotMessageSize();
82  void OnGotMessageBytes();
83
84  // Timeout handler.
85  void OnTimeout();
86
87  // Closes the current connection.
88  void CloseConnection();
89
90  // Timeout policy: the timeout is only enforced while waiting on the
91  // handshake (version and/or LoginResponse) or once at least a tag packet has
92  // been received. It is reset every time new data is received, and is
93  // only stopped when a full message is processed.
94  // TODO(zea): consider enforcing a separate timeout when waiting for
95  // a message to send.
96  const base::TimeDelta read_timeout_;
97  base::OneShotTimer<ConnectionHandlerImpl> read_timeout_timer_;
98
99  // This connection's socket and the input/output streams attached to it.
100  net::StreamSocket* socket_;
101  scoped_ptr<SocketInputStream> input_stream_;
102  scoped_ptr<SocketOutputStream> output_stream_;
103
104  // Whether the MCS login handshake has successfully completed. See Init(..)
105  // description for more info on what the handshake involves.
106  bool handshake_complete_;
107
108  // State for the message currently being processed, if there is one.
109  uint8 message_tag_;
110  uint32 message_size_;
111
112  ProtoReceivedCallback read_callback_;
113  ProtoSentCallback write_callback_;
114  ConnectionChangedCallback connection_callback_;
115
116  base::WeakPtrFactory<ConnectionHandlerImpl> weak_ptr_factory_;
117
118  DISALLOW_COPY_AND_ASSIGN(ConnectionHandlerImpl);
119};
120
121}  // namespace gcm
122
123#endif  // GOOGLE_APIS_GCM_ENGINE_CONNECTION_HANDLER_IMPL_H_
124