diff options
Diffstat (limited to 'net/spdy/spdy_session.h')
-rw-r--r-- | net/spdy/spdy_session.h | 131 |
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 { |