summaryrefslogtreecommitdiffstats
path: root/net/spdy/spdy_session.h
diff options
context:
space:
mode:
Diffstat (limited to 'net/spdy/spdy_session.h')
-rw-r--r--net/spdy/spdy_session.h131
1 files changed, 130 insertions, 1 deletions
diff --git a/net/spdy/spdy_session.h b/net/spdy/spdy_session.h
index ed00e4f..39480b9 100644
--- a/net/spdy/spdy_session.h
+++ b/net/spdy/spdy_session.h
@@ -103,7 +103,8 @@ class SpdySession : public base::RefCounted<SpdySession>,
// NOTE: This function can have false negatives on some platforms.
bool VerifyDomainAuthentication(const std::string& domain);
- // Send the SYN frame for |stream_id|.
+ // Send the SYN frame for |stream_id|. This also sends PING message to check
+ // the status of the connection.
int WriteSynStream(
spdy::SpdyStreamId stream_id,
RequestPriority priority,
@@ -154,6 +155,14 @@ class SpdySession : public base::RefCounted<SpdySession>,
return max_concurrent_stream_limit_;
}
+ // Enable sending of PING frame with each request.
+ static void set_enable_ping_based_connection_checking(bool enable) {
+ enable_ping_based_connection_checking_ = enable;
+ }
+ static bool enable_ping_based_connection_checking() {
+ return enable_ping_based_connection_checking_;
+ }
+
// Send WINDOW_UPDATE frame, called by a stream whenever receive window
// size is increased.
void SendWindowUpdate(spdy::SpdyStreamId stream_id, int delta_window_size);
@@ -208,6 +217,8 @@ class SpdySession : public base::RefCounted<SpdySession>,
private:
friend class base::RefCounted<SpdySession>;
+ // Allow tests to access our innards for testing purposes.
+ FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, Ping);
FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, GetActivePushStream);
struct PendingCreateStream {
@@ -270,6 +281,7 @@ class SpdySession : public base::RefCounted<SpdySession>,
const linked_ptr<spdy::SpdyHeaderBlock>& headers);
void OnRst(const spdy::SpdyRstStreamControlFrame& frame);
void OnGoAway(const spdy::SpdyGoAwayControlFrame& frame);
+ void OnPing(const spdy::SpdyPingControlFrame& frame);
void OnSettings(const spdy::SpdySettingsControlFrame& frame);
void OnWindowUpdate(const spdy::SpdyWindowUpdateControlFrame& frame);
@@ -284,6 +296,31 @@ class SpdySession : public base::RefCounted<SpdySession>,
// SETTINGS ontrol frame, update our SpdySession accordingly.
void HandleSettings(const spdy::SpdySettings& settings);
+ // Send the PING (preface-PING and trailing-PING) frames.
+ void SendPrefacePingIfNoneInFlight();
+
+ // Send PING if there are no PINGs in flight and we haven't heard from server.
+ void SendPrefacePing();
+
+ // Send a PING after delay. Don't post a PING if there is already
+ // a trailing PING pending.
+ void PlanToSendTrailingPing();
+
+ // Send a PING if there is no |trailing_ping_pending_|. This PING verifies
+ // that the requests are being received by the server.
+ void SendTrailingPing();
+
+ // Send the PING frame.
+ void WritePingFrame(uint32 unique_id);
+
+ // Post a CheckPingStatus call after delay. Don't post if there is already
+ // CheckPingStatus running.
+ void PlanToCheckPingStatus();
+
+ // Check the status of the connection. It calls |CloseSessionOnError| if we
+ // haven't received any data in |kHungInterval| time period.
+ void CheckPingStatus(base::TimeTicks last_check_time);
+
// Start reading from the socket.
// Returns OK on success, or an error on failure.
net::Error ReadSocket();
@@ -335,6 +372,46 @@ class SpdySession : public base::RefCounted<SpdySession>,
size_t len);
virtual void OnControl(const spdy::SpdyControlFrame* frame);
+ virtual bool OnControlFrameHeaderData(spdy::SpdyStreamId stream_id,
+ const char* header_data,
+ size_t len);
+
+ virtual void OnDataFrameHeader(const spdy::SpdyDataFrame* frame);
+
+ // --------------------------
+ // Helper methods for testing
+ // --------------------------
+ static void set_connection_at_risk_of_loss_ms(int duration) {
+ connection_at_risk_of_loss_ms_ = duration;
+ }
+ static int connection_at_risk_of_loss_ms() {
+ return connection_at_risk_of_loss_ms_;
+ }
+
+ static void set_trailing_ping_delay_time_ms(int duration) {
+ trailing_ping_delay_time_ms_ = duration;
+ }
+ static int trailing_ping_delay_time_ms() {
+ return trailing_ping_delay_time_ms_;
+ }
+
+ static void set_hung_interval_ms(int duration) {
+ hung_interval_ms_ = duration;
+ }
+ static int hung_interval_ms() {
+ return hung_interval_ms_;
+ }
+
+ int64 pings_in_flight() const { return pings_in_flight_; }
+
+ uint32 next_ping_id() const { return next_ping_id_; }
+
+ base::TimeTicks received_data_time() const { return received_data_time_; }
+
+ bool trailing_ping_pending() const { return trailing_ping_pending_; }
+
+ bool check_ping_status_pending() const { return check_ping_status_pending_; }
+
// Callbacks for the Spdy session.
CompletionCallbackImpl<SpdySession> read_callback_;
CompletionCallbackImpl<SpdySession> write_callback_;
@@ -424,6 +501,28 @@ class SpdySession : public base::RefCounted<SpdySession>,
// frame.
int stalled_streams_; // Count of streams that were ever stalled.
+ // Count of all pings on the wire, for which we have not gotten a response.
+ int64 pings_in_flight_;
+
+ // This is the next ping_id (unique_id) to be sent in PING frame.
+ uint32 next_ping_id_;
+
+ // This is the last time we have received data.
+ base::TimeTicks received_data_time_;
+
+ // Indicate if we have already scheduled a delayed task to send a trailing
+ // ping (and we never have more than one scheduled at a time).
+ bool trailing_ping_pending_;
+
+ // Indicate if we have already scheduled a delayed task to check the ping
+ // status.
+ bool check_ping_status_pending_;
+
+ // Indicate if we need to send a ping (generally, a trailing ping). This helps
+ // us to decide if we need yet another trailing ping, or if it would be a
+ // waste of effort (and MUST not be done).
+ bool need_to_send_ping_;
+
// Initial send window size for the session; can be changed by an
// arriving SETTINGS frame; newly created streams use this value for the
// initial send window size.
@@ -440,6 +539,36 @@ class SpdySession : public base::RefCounted<SpdySession>,
static bool use_ssl_;
static bool use_flow_control_;
static size_t max_concurrent_stream_limit_;
+
+ // This enables or disables connection health checking system.
+ static bool enable_ping_based_connection_checking_;
+
+ // |connection_at_risk_of_loss_ms_| is an optimization to avoid sending
+ // wasteful preface pings (when we just got some data).
+ //
+ // If it is zero (the most conservative figure), then we always send the
+ // preface ping (when none are in flight).
+ //
+ // It is common for TCP/IP sessions to time out in about 3-5 minutes.
+ // Certainly if it has been more than 3 minutes, we do want to send a preface
+ // ping.
+ //
+ // We don't think any connection will time out in under about 10 seconds. So
+ // this might as well be set to something conservative like 10 seconds. Later,
+ // we could adjust it to send fewer pings perhaps.
+ static int connection_at_risk_of_loss_ms_;
+
+ // This is the amount of time (in milliseconds) we wait before sending a
+ // trailing ping. We use a trailing ping (sent after all data) to get an
+ // effective acknowlegement from the server that it has indeed received all
+ // (prior) data frames. With that assurance, we are willing to enter into a
+ // wait state for responses to our last data frame(s) without further pings.
+ static int trailing_ping_delay_time_ms_;
+
+ // The amount of time (in milliseconds) that we are willing to tolerate with
+ // no data received (of any form), while there is a ping in flight, before we
+ // declare the connection to be hung.
+ static int hung_interval_ms_;
};
class NetLogSpdySynParameter : public NetLog::EventParameters {