| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef GOOGLE_APIS_GCM_ENGINE_CONNECTION_HANDLER_H_ | 5 #ifndef GOOGLE_APIS_GCM_ENGINE_CONNECTION_HANDLER_H_ |
| 6 #define GOOGLE_APIS_GCM_ENGINE_CONNECTION_HANDLER_H_ | 6 #define GOOGLE_APIS_GCM_ENGINE_CONNECTION_HANDLER_H_ |
| 7 | 7 |
| 8 #include "base/memory/weak_ptr.h" | 8 #include "base/callback.h" |
| 9 #include "base/timer/timer.h" | |
| 10 #include "google_apis/gcm/base/gcm_export.h" | 9 #include "google_apis/gcm/base/gcm_export.h" |
| 11 #include "google_apis/gcm/protocol/mcs.pb.h" | |
| 12 | 10 |
| 13 namespace net{ | 11 namespace net{ |
| 14 class StreamSocket; | 12 class StreamSocket; |
| 13 } // namespace net |
| 14 |
| 15 namespace google { |
| 16 namespace protobuf { |
| 17 class MessageLite; |
| 18 } // namespace protobuf |
| 19 } // namepsace google |
| 20 |
| 21 namespace mcs_proto { |
| 22 class LoginRequest; |
| 15 } | 23 } |
| 16 | 24 |
| 17 namespace gcm { | 25 namespace gcm { |
| 18 | 26 |
| 19 class SocketInputStream; | 27 class SocketInputStream; |
| 20 class SocketOutputStream; | 28 class SocketOutputStream; |
| 21 | 29 |
| 22 // Handles performing the protocol handshake and sending/receiving protobuf | 30 // Handles performing the protocol handshake and sending/receiving protobuf |
| 23 // messages. Note that no retrying or queueing is enforced at this layer. | 31 // messages. Note that no retrying or queueing is enforced at this layer. |
| 24 // Once a connection error is encountered, the ConnectionHandler will disconnect | 32 // Once a connection error is encountered, the ConnectionHandler will disconnect |
| 25 // the socket and must be reinitialized with a new StreamSocket before | 33 // the socket and must be reinitialized with a new StreamSocket before |
| 26 // messages can be sent/received again. | 34 // messages can be sent/received again. |
| 27 class GCM_EXPORT ConnectionHandler { | 35 class GCM_EXPORT ConnectionHandler { |
| 28 public: | 36 public: |
| 29 typedef base::Callback<void(scoped_ptr<google::protobuf::MessageLite>)> | 37 typedef base::Callback<void(scoped_ptr<google::protobuf::MessageLite>)> |
| 30 ProtoReceivedCallback; | 38 ProtoReceivedCallback; |
| 31 typedef base::Closure ProtoSentCallback; | 39 typedef base::Closure ProtoSentCallback; |
| 32 typedef base::Callback<void(int)> ConnectionChangedCallback; | 40 typedef base::Callback<void(int)> ConnectionChangedCallback; |
| 33 | 41 |
| 34 explicit ConnectionHandler(base::TimeDelta read_timeout); | 42 ConnectionHandler(); |
| 35 ~ConnectionHandler(); | 43 virtual ~ConnectionHandler(); |
| 36 | 44 |
| 37 // Starts a new MCS connection handshake (using |login_request|) and, upon | 45 // Starts a new MCS connection handshake (using |login_request|) and, upon |
| 38 // success, begins listening for incoming/outgoing messages. A successful | 46 // success, begins listening for incoming/outgoing messages. |
| 39 // handshake is when a mcs_proto::LoginResponse is received, and is signaled | |
| 40 // via the |read_callback|. | |
| 41 // Outputs: | |
| 42 // |read_callback| will be invoked with the contents of any received protobuf | |
| 43 // message. | |
| 44 // |write_callback| will be invoked anytime a message has been successfully | |
| 45 // sent. Note: this just means the data was sent to the wire, not that the | |
| 46 // other end received it. | |
| 47 // |connection_callback| will be invoked with any fatal read/write errors | |
| 48 // encountered. | |
| 49 // | 47 // |
| 50 // Note: It is correct and expected to call Init more than once, as connection | 48 // Note: It is correct and expected to call Init more than once, as connection |
| 51 // issues are encountered and new connections must be made. | 49 // issues are encountered and new connections must be made. |
| 52 void Init(scoped_ptr<net::StreamSocket> socket, | 50 virtual void Init(const mcs_proto::LoginRequest& login_request, |
| 53 const google::protobuf::MessageLite& login_request, | 51 scoped_ptr<net::StreamSocket> socket) = 0; |
| 54 const ProtoReceivedCallback& read_callback, | |
| 55 const ProtoSentCallback& write_callback, | |
| 56 const ConnectionChangedCallback& connection_callback); | |
| 57 | 52 |
| 58 // Checks that a handshake has been completed and a message is not already | 53 // Checks that a handshake has been completed and a message is not already |
| 59 // in flight. | 54 // in flight. |
| 60 bool CanSendMessage() const; | 55 virtual bool CanSendMessage() const = 0; |
| 61 | 56 |
| 62 // Send an MCS protobuf message. CanSendMessage() must be true. | 57 // Send an MCS protobuf message. CanSendMessage() must be true. |
| 63 void SendMessage(const google::protobuf::MessageLite& message); | 58 virtual void SendMessage(const google::protobuf::MessageLite& message) = 0; |
| 64 | |
| 65 private: | |
| 66 // State machine for handling incoming data. See WaitForData(..) for usage. | |
| 67 enum ProcessingState { | |
| 68 // Processing the version, tag, and size packets (assuming minimum length | |
| 69 // size packet). Only used during the login handshake. | |
| 70 MCS_VERSION_TAG_AND_SIZE = 0, | |
| 71 // Processing the tag and size packets (assuming minimum length size | |
| 72 // packet). Used for normal messages. | |
| 73 MCS_TAG_AND_SIZE, | |
| 74 // Processing a maximum length size packet (for messages with length > 128). | |
| 75 // Used when a normal size packet was not sufficient to read the message | |
| 76 // size. | |
| 77 MCS_FULL_SIZE, | |
| 78 // Processing the protocol buffer bytes (for those messages with non-zero | |
| 79 // sizes). | |
| 80 MCS_PROTO_BYTES | |
| 81 }; | |
| 82 | |
| 83 // Sends the protocol version and login request. First step in the MCS | |
| 84 // connection handshake. | |
| 85 void Login(const google::protobuf::MessageLite& login_request); | |
| 86 | |
| 87 // SendMessage continuation. Invoked when Socket::Write completes. | |
| 88 void OnMessageSent(); | |
| 89 | |
| 90 // Starts the message processing process, which is comprised of the tag, | |
| 91 // message size, and bytes packet types. | |
| 92 void GetNextMessage(); | |
| 93 | |
| 94 // Performs any necessary SocketInputStream refreshing until the data | |
| 95 // associated with |packet_type| is fully ready, then calls the appropriate | |
| 96 // OnGot* message to process the packet data. If the read times out, | |
| 97 // will close the stream and invoke the connection callback. | |
| 98 void WaitForData(ProcessingState state); | |
| 99 | |
| 100 // Incoming data helper methods. | |
| 101 void OnGotVersion(); | |
| 102 void OnGotMessageTag(); | |
| 103 void OnGotMessageSize(); | |
| 104 void OnGotMessageBytes(); | |
| 105 | |
| 106 // Timeout handler. | |
| 107 void OnTimeout(); | |
| 108 | |
| 109 // Closes the current connection. | |
| 110 void CloseConnection(); | |
| 111 | |
| 112 // Timeout policy: the timeout is only enforced while waiting on the | |
| 113 // handshake (version and/or LoginResponse) or once at least a tag packet has | |
| 114 // been received. It is reset every time new data is received, and is | |
| 115 // only stopped when a full message is processed. | |
| 116 // TODO(zea): consider enforcing a separate timeout when waiting for | |
| 117 // a message to send. | |
| 118 const base::TimeDelta read_timeout_; | |
| 119 base::OneShotTimer<ConnectionHandler> read_timeout_timer_; | |
| 120 | |
| 121 // This connection's socket and the input/output streams attached to it. | |
| 122 scoped_ptr<net::StreamSocket> socket_; | |
| 123 scoped_ptr<SocketInputStream> input_stream_; | |
| 124 scoped_ptr<SocketOutputStream> output_stream_; | |
| 125 | |
| 126 // Whether the MCS login handshake has successfully completed. See Init(..) | |
| 127 // description for more info on what the handshake involves. | |
| 128 bool handshake_complete_; | |
| 129 | |
| 130 // State for the message currently being processed, if there is one. | |
| 131 uint8 message_tag_; | |
| 132 uint32 message_size_; | |
| 133 | |
| 134 ProtoReceivedCallback read_callback_; | |
| 135 ProtoSentCallback write_callback_; | |
| 136 ConnectionChangedCallback connection_callback_; | |
| 137 | |
| 138 base::WeakPtrFactory<ConnectionHandler> weak_ptr_factory_; | |
| 139 | |
| 140 DISALLOW_COPY_AND_ASSIGN(ConnectionHandler); | |
| 141 }; | 59 }; |
| 142 | 60 |
| 143 } // namespace gcm | 61 } // namespace gcm |
| 144 | 62 |
| 145 #endif // GOOGLE_APIS_GCM_ENGINE_CONNECTION_HANDLER_H_ | 63 #endif // GOOGLE_APIS_GCM_ENGINE_CONNECTION_HANDLER_H_ |
| OLD | NEW |