Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(107)

Unified Diff: net/spdy/spdy_session.cc

Issue 8230037: Send PING to check the status of the SPDY connection. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« net/base/net_log_event_type_list.h ('K') | « net/spdy/spdy_session.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/spdy/spdy_session.cc
===================================================================
--- net/spdy/spdy_session.cc (revision 105257)
+++ net/spdy/spdy_session.cc (working copy)
@@ -4,6 +4,7 @@
#include "net/spdy/spdy_session.h"
+#include "base/auto_reset.h"
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/memory/linked_ptr.h"
@@ -172,6 +173,23 @@
DISALLOW_COPY_AND_ASSIGN(NetLogSpdyRstParameter);
};
+class NetLogSpdyPingParameter : public NetLog::EventParameters {
+ public:
+ explicit NetLogSpdyPingParameter(uint32 unique_id) : unique_id_(unique_id) {}
+
+ virtual Value* ToValue() const {
+ DictionaryValue* dict = new DictionaryValue();
+ dict->SetInteger("unique_id", unique_id_);
+ return dict;
+ }
+
+ private:
+ ~NetLogSpdyPingParameter() {}
+ const uint32 unique_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetLogSpdyPingParameter);
+};
+
class NetLogSpdyGoAwayParameter : public NetLog::EventParameters {
public:
NetLogSpdyGoAwayParameter(spdy::SpdyStreamId last_stream_id,
@@ -243,6 +261,9 @@
sent_settings_(false),
received_settings_(false),
stalled_streams_(0),
+ pings_in_flight_(0),
+ unique_id_counter_(1),
+ follower_ping_pending_(false),
initial_send_window_size_(spdy::kSpdyStreamInitialWindowSize),
initial_recv_window_size_(spdy::kSpdyStreamInitialWindowSize),
net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SPDY_SESSION)),
@@ -471,6 +492,10 @@
const scoped_refptr<SpdyStream>& stream = active_streams_[stream_id];
CHECK_EQ(stream->stream_id(), stream_id);
+ int result = SendPing(stream_id);
willchan no longer on Chromium 2011/10/13 06:38:39 You should queue this _after_ the SYN_STREAM. We d
willchan no longer on Chromium 2011/10/13 15:47:17 You didn't address this comment.
ramant (doing other things) 2011/10/13 21:41:14 Jim said Roberto wanted us to send the pre-ping re
+ if (result != ERR_IO_PENDING)
+ return result;
+
scoped_ptr<spdy::SpdySynStreamControlFrame> syn_frame(
spdy_framer_.CreateSynStream(
stream_id, 0,
@@ -609,6 +634,8 @@
bytes_received_ += bytes_read;
+ received_data_time_ = base::TimeTicks::Now();
+
// The SpdyFramer will use callbacks onto |this| as it parses frames.
// When errors occur, those callbacks can lead to teardown of all references
// to |this|, so maintain a reference to self during this call for safe
@@ -630,6 +657,10 @@
}
void SpdySession::OnWriteComplete(int result) {
+ OnWriteCompleteInternal(result, false);
+}
+
+void SpdySession::OnWriteCompleteInternal(int result, bool ping_frame) {
willchan no longer on Chromium 2011/10/13 06:38:39 You shouldn't need this extra bool parameter.
ramant (doing other things) 2011/10/13 21:41:14 Done.
DCHECK(write_pending_);
DCHECK(in_flight_write_.size());
@@ -659,7 +690,7 @@
// It is possible that the stream was cancelled while we were writing
// to the socket.
- if (!stream->cancelled())
+ if (!stream->cancelled() && !ping_frame)
stream->OnWriteComplete(result);
}
@@ -746,6 +777,7 @@
// Loop sending frames until we've sent everything or until the write
// returns error (or ERR_IO_PENDING).
while (in_flight_write_.buffer() || !queue_.empty()) {
+ bool ping_frame = false;
willchan no longer on Chromium 2011/10/13 06:38:39 You shouldn't need this.
ramant (doing other things) 2011/10/13 21:41:14 Done.
if (!in_flight_write_.buffer()) {
// Grab the next SpdyFrame to send.
SpdyIOBuffer next_buffer = queue_.top();
@@ -777,6 +809,8 @@
} else {
size = uncompressed_frame.length() + spdy::SpdyFrame::size();
in_flight_write_ = next_buffer;
+ if (spdy_framer_.IsPingFrame(uncompressed_frame))
+ ping_frame = true;
}
} else {
DCHECK(in_flight_write_.buffer()->BytesRemaining());
@@ -789,7 +823,7 @@
break;
// We sent the frame successfully.
- OnWriteComplete(rv);
+ OnWriteCompleteInternal(rv, ping_frame);
// TODO(mbelshe): Test this error case. Maybe we should mark the socket
// as in an error state.
@@ -1226,6 +1260,9 @@
case spdy::GOAWAY:
OnGoAway(*reinterpret_cast<const spdy::SpdyGoAwayControlFrame*>(frame));
break;
+ case spdy::PING:
+ OnPing(*reinterpret_cast<const spdy::SpdyPingControlFrame*>(frame));
+ break;
case spdy::SETTINGS:
OnSettings(
*reinterpret_cast<const spdy::SpdySettingsControlFrame*>(frame));
@@ -1314,6 +1351,13 @@
// closed.
}
+void SpdySession::OnPing(const spdy::SpdyPingControlFrame& frame) {
+ --pings_in_flight_;
+ net_log_.AddEvent(
+ NetLog::TYPE_SPDY_SESSION_PING,
+ make_scoped_refptr(new NetLogSpdyPingParameter(frame.unique_id())));
+}
+
void SpdySession::OnSettings(const spdy::SpdySettingsControlFrame& frame) {
spdy::SpdySettings settings;
if (spdy_framer_.ParseSettings(&frame, &settings)) {
@@ -1452,6 +1496,105 @@
}
}
+int SpdySession::SendPing(spdy::SpdyStreamId stream_id) {
+ const base::TimeDelta kInterval = base::TimeDelta::FromMilliseconds(10000);
willchan no longer on Chromium 2011/10/13 06:38:39 Wow, this logic is not what we had discussed in th
willchan no longer on Chromium 2011/10/13 15:10:53 From Raman: """ pre-PING and post-PING came after
ramant (doing other things) 2011/10/13 21:41:14 Sorry about that.
+
+ base::TimeTicks now = base::TimeTicks::Now();
+ // If there are no PINGs in flight and we haven't heard from server, then
+ // send a pre-PING.
+ if ((pings_in_flight_ == 0) && ((now - received_data_time_) > kInterval)) {
+ int result = SendPrePing(stream_id);
+ if (result != ERR_IO_PENDING)
+ return result;
+ }
+
+ // Send a post-PING after a delay to make sure request has been received by
+ // the server.
+ const int kRequestTimeMs = 5000;
+ if (!follower_ping_pending_) {
+ follower_ping_pending_ = true;
+ MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &SpdySession::SendPostPing, stream_id),
+ kRequestTimeMs);
+
+ // Post a task to check the status of the connection.
+ const int kCheckStatusTimeMs = 10000;
+ MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &SpdySession::CheckStatus, stream_id, now),
+ kCheckStatusTimeMs);
+ }
+ return ERR_IO_PENDING;
+}
+
+int SpdySession::SendPrePing(spdy::SpdyStreamId stream_id) {
+ // Delay the writing of the PING frame so that it goes along with other
+ // frames.
+ AutoReset<bool> reset(&delayed_write_pending_, true);
+ return WritePingFrame(stream_id);
+}
+
+int SpdySession::SendPostPing(spdy::SpdyStreamId stream_id) {
+ DCHECK(follower_ping_pending_);
+ follower_ping_pending_ = false;
+ return WritePingFrame(stream_id);
+}
+
+int SpdySession::WritePingFrame(spdy::SpdyStreamId stream_id) {
+ // Find our stream.
+ if (!IsStreamActive(stream_id))
+ return ERR_INVALID_SPDY_STREAM;
+ const scoped_refptr<SpdyStream>& stream = active_streams_[stream_id];
+ CHECK_EQ(stream->stream_id(), stream_id);
+
+ scoped_ptr<spdy::SpdyPingControlFrame> ping_frame(
+ spdy_framer_.CreatePingFrame(unique_id_counter_));
+ QueueFrame(ping_frame.get(), SPDY_PRIORITY_HIGHEST, stream);
willchan no longer on Chromium 2011/10/13 06:38:39 Here's the problem. Pass a NULL stream to QueueFra
ramant (doing other things) 2011/10/13 21:41:14 Done.
+
+ if (net_log().IsLoggingAllEvents()) {
+ net_log().AddEvent(
+ NetLog::TYPE_SPDY_SESSION_PING,
+ make_scoped_refptr(new NetLogSpdyPingParameter(unique_id_counter_)));
+ }
+
+ ++pings_in_flight_;
+ unique_id_counter_ += 2;
+ return ERR_IO_PENDING;
+}
+
+void SpdySession::CheckStatus(spdy::SpdyStreamId stream_id,
+ base::TimeTicks last_check_time) {
+ // Find our stream.
+ if (!IsStreamActive(stream_id))
+ return;
+ const scoped_refptr<SpdyStream>& stream = active_streams_[stream_id];
+ CHECK_EQ(stream->stream_id(), stream_id);
+
+ // Check if we got a response back for all PINGs we had sent.
+ if (pings_in_flight_ == 0)
+ return;
+
+ // Check if we haven't received any data in |kHungInterval|.
+ const base::TimeDelta kHungInterval = base::TimeDelta::FromSeconds(10);
+ if (received_data_time_ < last_check_time) {
+ DCHECK(base::TimeTicks::Now() - received_data_time_ > kHungInterval);
+ DeleteStream(stream_id, ERR_SPDY_PING_FAILED);
+ return;
+ }
+
+ // Check the status of connection after a delay.
+ base::TimeTicks now = base::TimeTicks::Now();
+ base::TimeDelta delay = now - received_data_time_ + kHungInterval;
+ MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &SpdySession::CheckStatus, stream_id, now),
+ delay.InMilliseconds());
+}
+
void SpdySession::RecordHistograms() {
UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPerSession",
streams_initiated_count_,
« net/base/net_log_event_type_list.h ('K') | « net/spdy/spdy_session.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698