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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
« net/spdy/spdy_session.h ('K') | « net/spdy/spdy_session.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 #include "net/spdy/spdy_session.h" 5 #include "net/spdy/spdy_session.h"
6 6
7 #include "base/auto_reset.h"
7 #include "base/basictypes.h" 8 #include "base/basictypes.h"
8 #include "base/logging.h" 9 #include "base/logging.h"
9 #include "base/memory/linked_ptr.h" 10 #include "base/memory/linked_ptr.h"
10 #include "base/message_loop.h" 11 #include "base/message_loop.h"
11 #include "base/metrics/field_trial.h" 12 #include "base/metrics/field_trial.h"
12 #include "base/metrics/stats_counters.h" 13 #include "base/metrics/stats_counters.h"
13 #include "base/stl_util.h" 14 #include "base/stl_util.h"
14 #include "base/string_number_conversions.h" 15 #include "base/string_number_conversions.h"
15 #include "base/string_util.h" 16 #include "base/string_util.h"
16 #include "base/stringprintf.h" 17 #include "base/stringprintf.h"
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
165 } 166 }
166 167
167 private: 168 private:
168 ~NetLogSpdyRstParameter() {} 169 ~NetLogSpdyRstParameter() {}
169 const spdy::SpdyStreamId stream_id_; 170 const spdy::SpdyStreamId stream_id_;
170 const int status_; 171 const int status_;
171 172
172 DISALLOW_COPY_AND_ASSIGN(NetLogSpdyRstParameter); 173 DISALLOW_COPY_AND_ASSIGN(NetLogSpdyRstParameter);
173 }; 174 };
174 175
176 class NetLogSpdyPingParameter : public NetLog::EventParameters {
177 public:
178 explicit NetLogSpdyPingParameter(uint32 unique_id) : unique_id_(unique_id) {}
179
180 virtual Value* ToValue() const {
181 DictionaryValue* dict = new DictionaryValue();
182 dict->SetInteger("unique_id", unique_id_);
183 return dict;
184 }
185
186 private:
187 ~NetLogSpdyPingParameter() {}
188 const uint32 unique_id_;
189
190 DISALLOW_COPY_AND_ASSIGN(NetLogSpdyPingParameter);
191 };
192
175 class NetLogSpdyGoAwayParameter : public NetLog::EventParameters { 193 class NetLogSpdyGoAwayParameter : public NetLog::EventParameters {
176 public: 194 public:
177 NetLogSpdyGoAwayParameter(spdy::SpdyStreamId last_stream_id, 195 NetLogSpdyGoAwayParameter(spdy::SpdyStreamId last_stream_id,
178 int active_streams, 196 int active_streams,
179 int unclaimed_streams) 197 int unclaimed_streams)
180 : last_stream_id_(last_stream_id), 198 : last_stream_id_(last_stream_id),
181 active_streams_(active_streams), 199 active_streams_(active_streams),
182 unclaimed_streams_(unclaimed_streams) {} 200 unclaimed_streams_(unclaimed_streams) {}
183 201
184 virtual Value* ToValue() const { 202 virtual Value* ToValue() const {
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
239 max_concurrent_streams_(init_max_concurrent_streams_), 257 max_concurrent_streams_(init_max_concurrent_streams_),
240 streams_initiated_count_(0), 258 streams_initiated_count_(0),
241 streams_pushed_count_(0), 259 streams_pushed_count_(0),
242 streams_pushed_and_claimed_count_(0), 260 streams_pushed_and_claimed_count_(0),
243 streams_abandoned_count_(0), 261 streams_abandoned_count_(0),
244 frames_received_(0), 262 frames_received_(0),
245 bytes_received_(0), 263 bytes_received_(0),
246 sent_settings_(false), 264 sent_settings_(false),
247 received_settings_(false), 265 received_settings_(false),
248 stalled_streams_(0), 266 stalled_streams_(0),
267 pings_in_flight_(0),
268 unique_id_counter_(1),
269 follower_ping_pending_(false),
249 initial_send_window_size_(spdy::kSpdyStreamInitialWindowSize), 270 initial_send_window_size_(spdy::kSpdyStreamInitialWindowSize),
250 initial_recv_window_size_(spdy::kSpdyStreamInitialWindowSize), 271 initial_recv_window_size_(spdy::kSpdyStreamInitialWindowSize),
251 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SPDY_SESSION)), 272 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SPDY_SESSION)),
252 verify_domain_authentication_(verify_domain_authentication) { 273 verify_domain_authentication_(verify_domain_authentication) {
253 DCHECK(HttpStreamFactory::spdy_enabled()); 274 DCHECK(HttpStreamFactory::spdy_enabled());
254 net_log_.BeginEvent( 275 net_log_.BeginEvent(
255 NetLog::TYPE_SPDY_SESSION, 276 NetLog::TYPE_SPDY_SESSION,
256 make_scoped_refptr( 277 make_scoped_refptr(
257 new NetLogSpdySessionParameter(host_port_proxy_pair_))); 278 new NetLogSpdySessionParameter(host_port_proxy_pair_)));
258 279
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after
467 spdy::SpdyStreamId stream_id, 488 spdy::SpdyStreamId stream_id,
468 RequestPriority priority, 489 RequestPriority priority,
469 spdy::SpdyControlFlags flags, 490 spdy::SpdyControlFlags flags,
470 const linked_ptr<spdy::SpdyHeaderBlock>& headers) { 491 const linked_ptr<spdy::SpdyHeaderBlock>& headers) {
471 // Find our stream 492 // Find our stream
472 if (!IsStreamActive(stream_id)) 493 if (!IsStreamActive(stream_id))
473 return ERR_INVALID_SPDY_STREAM; 494 return ERR_INVALID_SPDY_STREAM;
474 const scoped_refptr<SpdyStream>& stream = active_streams_[stream_id]; 495 const scoped_refptr<SpdyStream>& stream = active_streams_[stream_id];
475 CHECK_EQ(stream->stream_id(), stream_id); 496 CHECK_EQ(stream->stream_id(), stream_id);
476 497
498 int result = SendPing(stream_id);
499 if (result != ERR_IO_PENDING)
500 return result;
501
477 scoped_ptr<spdy::SpdySynStreamControlFrame> syn_frame( 502 scoped_ptr<spdy::SpdySynStreamControlFrame> syn_frame(
478 spdy_framer_.CreateSynStream( 503 spdy_framer_.CreateSynStream(
479 stream_id, 0, 504 stream_id, 0,
480 ConvertRequestPriorityToSpdyPriority(priority), 505 ConvertRequestPriorityToSpdyPriority(priority),
481 flags, false, headers.get())); 506 flags, false, headers.get()));
482 QueueFrame(syn_frame.get(), priority, stream); 507 QueueFrame(syn_frame.get(), priority, stream);
483 508
484 base::StatsCounter spdy_requests("spdy.requests"); 509 base::StatsCounter spdy_requests("spdy.requests");
485 spdy_requests.Increment(); 510 spdy_requests.Increment();
486 streams_initiated_count_++; 511 streams_initiated_count_++;
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
605 // Session is tearing down. 630 // Session is tearing down.
606 net::Error error = static_cast<net::Error>(bytes_read); 631 net::Error error = static_cast<net::Error>(bytes_read);
607 if (bytes_read == 0) 632 if (bytes_read == 0)
608 error = ERR_CONNECTION_CLOSED; 633 error = ERR_CONNECTION_CLOSED;
609 CloseSessionOnError(error, true); 634 CloseSessionOnError(error, true);
610 return; 635 return;
611 } 636 }
612 637
613 bytes_received_ += bytes_read; 638 bytes_received_ += bytes_read;
614 639
640 received_data_time_ = base::TimeTicks::Now();
641
615 // The SpdyFramer will use callbacks onto |this| as it parses frames. 642 // The SpdyFramer will use callbacks onto |this| as it parses frames.
616 // When errors occur, those callbacks can lead to teardown of all references 643 // When errors occur, those callbacks can lead to teardown of all references
617 // to |this|, so maintain a reference to self during this call for safe 644 // to |this|, so maintain a reference to self during this call for safe
618 // cleanup. 645 // cleanup.
619 scoped_refptr<SpdySession> self(this); 646 scoped_refptr<SpdySession> self(this);
620 647
621 char *data = read_buffer_->data(); 648 char *data = read_buffer_->data();
622 while (bytes_read && 649 while (bytes_read &&
623 spdy_framer_.error_code() == spdy::SpdyFramer::SPDY_NO_ERROR) { 650 spdy_framer_.error_code() == spdy::SpdyFramer::SPDY_NO_ERROR) {
624 uint32 bytes_processed = spdy_framer_.ProcessInput(data, bytes_read); 651 uint32 bytes_processed = spdy_framer_.ProcessInput(data, bytes_read);
(...skipping 597 matching lines...) Expand 10 before | Expand all | Expand 10 after
1222 return; 1249 return;
1223 } 1250 }
1224 } 1251 }
1225 1252
1226 frames_received_++; 1253 frames_received_++;
1227 1254
1228 switch (type) { 1255 switch (type) {
1229 case spdy::GOAWAY: 1256 case spdy::GOAWAY:
1230 OnGoAway(*reinterpret_cast<const spdy::SpdyGoAwayControlFrame*>(frame)); 1257 OnGoAway(*reinterpret_cast<const spdy::SpdyGoAwayControlFrame*>(frame));
1231 break; 1258 break;
1259 case spdy::PING:
1260 OnPing(*reinterpret_cast<const spdy::SpdyPingControlFrame*>(frame));
1261 break;
1232 case spdy::SETTINGS: 1262 case spdy::SETTINGS:
1233 OnSettings( 1263 OnSettings(
1234 *reinterpret_cast<const spdy::SpdySettingsControlFrame*>(frame)); 1264 *reinterpret_cast<const spdy::SpdySettingsControlFrame*>(frame));
1235 break; 1265 break;
1236 case spdy::RST_STREAM: 1266 case spdy::RST_STREAM:
1237 OnRst(*reinterpret_cast<const spdy::SpdyRstStreamControlFrame*>(frame)); 1267 OnRst(*reinterpret_cast<const spdy::SpdyRstStreamControlFrame*>(frame));
1238 break; 1268 break;
1239 case spdy::SYN_STREAM: 1269 case spdy::SYN_STREAM:
1240 OnSyn(*reinterpret_cast<const spdy::SpdySynStreamControlFrame*>(frame), 1270 OnSyn(*reinterpret_cast<const spdy::SpdySynStreamControlFrame*>(frame),
1241 headers); 1271 headers);
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
1310 CloseAllStreams(net::ERR_ABORTED); 1340 CloseAllStreams(net::ERR_ABORTED);
1311 1341
1312 // TODO(willchan): Cancel any streams that are past the GoAway frame's 1342 // TODO(willchan): Cancel any streams that are past the GoAway frame's
1313 // |last_accepted_stream_id|. 1343 // |last_accepted_stream_id|.
1314 1344
1315 // Don't bother killing any streams that are still reading. They'll either 1345 // Don't bother killing any streams that are still reading. They'll either
1316 // complete successfully or get an ERR_CONNECTION_CLOSED when the socket is 1346 // complete successfully or get an ERR_CONNECTION_CLOSED when the socket is
1317 // closed. 1347 // closed.
1318 } 1348 }
1319 1349
1350 void SpdySession::OnPing(const spdy::SpdyPingControlFrame& frame) {
1351 --pings_in_flight_;
willchan no longer on Chromium 2011/10/13 15:47:17 If you aren't doing any PING validation of the uni
ramant (doing other things) 2011/10/13 21:41:14 Decrements pings_in_flight_ only if client had sen
1352 net_log_.AddEvent(
1353 NetLog::TYPE_SPDY_SESSION_PING,
1354 make_scoped_refptr(new NetLogSpdyPingParameter(frame.unique_id())));
1355 }
1356
1320 void SpdySession::OnSettings(const spdy::SpdySettingsControlFrame& frame) { 1357 void SpdySession::OnSettings(const spdy::SpdySettingsControlFrame& frame) {
1321 spdy::SpdySettings settings; 1358 spdy::SpdySettings settings;
1322 if (spdy_framer_.ParseSettings(&frame, &settings)) { 1359 if (spdy_framer_.ParseSettings(&frame, &settings)) {
1323 HandleSettings(settings); 1360 HandleSettings(settings);
1324 spdy_settings_->Set(host_port_pair(), settings); 1361 spdy_settings_->Set(host_port_pair(), settings);
1325 } 1362 }
1326 1363
1327 received_settings_ = true; 1364 received_settings_ = true;
1328 1365
1329 net_log_.AddEvent( 1366 net_log_.AddEvent(
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
1448 switch (id) { 1485 switch (id) {
1449 case spdy::SETTINGS_MAX_CONCURRENT_STREAMS: 1486 case spdy::SETTINGS_MAX_CONCURRENT_STREAMS:
1450 max_concurrent_streams_ = std::min(static_cast<size_t>(val), 1487 max_concurrent_streams_ = std::min(static_cast<size_t>(val),
1451 max_concurrent_stream_limit_); 1488 max_concurrent_stream_limit_);
1452 ProcessPendingCreateStreams(); 1489 ProcessPendingCreateStreams();
1453 break; 1490 break;
1454 } 1491 }
1455 } 1492 }
1456 } 1493 }
1457 1494
1495 int SpdySession::SendPing(spdy::SpdyStreamId stream_id) {
1496 const base::TimeDelta kInterval = base::TimeDelta::FromMilliseconds(10000);
1497
1498 base::TimeTicks now = base::TimeTicks::Now();
1499 // If there are no PINGs in flight and we haven't heard from server, then
1500 // send a pre-PING.
1501 if ((pings_in_flight_ == 0) && ((now - received_data_time_) > kInterval)) {
1502 int result = SendPrePing(stream_id);
1503 if (result != ERR_IO_PENDING)
1504 return result;
1505 }
1506
1507 // Send a post-PING after a delay to make sure request has been received by
1508 // the server.
1509 const int kRequestTimeMs = 5000;
1510 if (!follower_ping_pending_) {
willchan no longer on Chromium 2011/10/13 15:47:17 What's the difference between a follower_ping and
ramant (doing other things) 2011/10/13 21:41:14 Used the word post_ping everywhere (sorry for usin
1511 follower_ping_pending_ = true;
1512 MessageLoop::current()->PostDelayedTask(
1513 FROM_HERE,
1514 method_factory_.NewRunnableMethod(
1515 &SpdySession::SendPostPing, stream_id),
1516 kRequestTimeMs);
1517
1518 // Post a task to check the status of the connection.
1519 const int kCheckStatusTimeMs = 10000;
1520 MessageLoop::current()->PostDelayedTask(
1521 FROM_HERE,
1522 method_factory_.NewRunnableMethod(
1523 &SpdySession::CheckStatus, stream_id, now),
1524 kCheckStatusTimeMs);
1525 }
1526 return ERR_IO_PENDING;
1527 }
1528
1529 int SpdySession::SendPrePing(spdy::SpdyStreamId stream_id) {
1530 // Delay the writing of the PING frame so that it goes along with other
1531 // frames.
willchan no longer on Chromium 2011/10/13 15:47:17 What does this comment mean? What is supposed to h
ramant (doing other things) 2011/10/13 21:41:14 My intention is not to send PING frame as a separa
1532 AutoReset<bool> reset(&delayed_write_pending_, true);
1533 return WritePingFrame(stream_id);
1534 }
1535
1536 int SpdySession::SendPostPing(spdy::SpdyStreamId stream_id) {
1537 DCHECK(follower_ping_pending_);
1538 follower_ping_pending_ = false;
1539 return WritePingFrame(stream_id);
1540 }
1541
1542 int SpdySession::WritePingFrame(spdy::SpdyStreamId stream_id) {
1543 // Find our stream.
1544 if (!IsStreamActive(stream_id))
willchan no longer on Chromium 2011/10/13 15:47:17 Why is WritePingFrame() looking up the stream?
ramant (doing other things) 2011/10/13 21:41:14 Deleted the use of stream_id from all PING related
1545 return ERR_INVALID_SPDY_STREAM;
1546 const scoped_refptr<SpdyStream>& stream = active_streams_[stream_id];
1547 CHECK_EQ(stream->stream_id(), stream_id);
1548
1549 scoped_ptr<spdy::SpdyPingControlFrame> ping_frame(
1550 spdy_framer_.CreatePingFrame(unique_id_counter_));
1551 QueueFrame(ping_frame.get(), SPDY_PRIORITY_HIGHEST, NULL);
1552
1553 if (net_log().IsLoggingAllEvents()) {
1554 net_log().AddEvent(
1555 NetLog::TYPE_SPDY_SESSION_PING,
1556 make_scoped_refptr(new NetLogSpdyPingParameter(unique_id_counter_)));
1557 }
1558
1559 ++pings_in_flight_;
1560 unique_id_counter_ += 2;
1561 return ERR_IO_PENDING;
1562 }
1563
1564 void SpdySession::CheckStatus(spdy::SpdyStreamId stream_id,
1565 base::TimeTicks last_check_time) {
1566 // Find our stream.
1567 if (!IsStreamActive(stream_id))
1568 return;
1569 const scoped_refptr<SpdyStream>& stream = active_streams_[stream_id];
1570 CHECK_EQ(stream->stream_id(), stream_id);
1571
1572 // Check if we got a response back for all PINGs we had sent.
1573 if (pings_in_flight_ == 0)
1574 return;
1575
1576 // Check if we haven't received any data in |kHungInterval|.
1577 const base::TimeDelta kHungInterval = base::TimeDelta::FromSeconds(10);
1578 if (received_data_time_ < last_check_time) {
1579 DCHECK(base::TimeTicks::Now() - received_data_time_ > kHungInterval);
1580 DeleteStream(stream_id, ERR_SPDY_PING_FAILED);
1581 return;
1582 }
1583
1584 // Check the status of connection after a delay.
1585 base::TimeTicks now = base::TimeTicks::Now();
1586 base::TimeDelta delay = now - received_data_time_ + kHungInterval;
willchan no longer on Chromium 2011/10/13 15:47:17 Is this math right? Shouldn't it be kHungInterval
ramant (doing other things) 2011/10/13 21:41:14 Done.
1587 MessageLoop::current()->PostDelayedTask(
1588 FROM_HERE,
1589 method_factory_.NewRunnableMethod(
1590 &SpdySession::CheckStatus, stream_id, now),
1591 delay.InMilliseconds());
1592 }
1593
1458 void SpdySession::RecordHistograms() { 1594 void SpdySession::RecordHistograms() {
1459 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPerSession", 1595 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPerSession",
1460 streams_initiated_count_, 1596 streams_initiated_count_,
1461 0, 300, 50); 1597 0, 300, 50);
1462 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPushedPerSession", 1598 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPushedPerSession",
1463 streams_pushed_count_, 1599 streams_pushed_count_,
1464 0, 300, 50); 1600 0, 300, 50);
1465 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPushedAndClaimedPerSession", 1601 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdyStreamsPushedAndClaimedPerSession",
1466 streams_pushed_and_claimed_count_, 1602 streams_pushed_and_claimed_count_,
1467 0, 300, 50); 1603 0, 300, 50);
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
1536 if (it == pending_callback_map_.end()) 1672 if (it == pending_callback_map_.end())
1537 return; 1673 return;
1538 1674
1539 OldCompletionCallback* callback = it->second.callback; 1675 OldCompletionCallback* callback = it->second.callback;
1540 int result = it->second.result; 1676 int result = it->second.result;
1541 pending_callback_map_.erase(it); 1677 pending_callback_map_.erase(it);
1542 callback->Run(result); 1678 callback->Run(result);
1543 } 1679 }
1544 1680
1545 } // namespace net 1681 } // namespace net
OLDNEW
« net/spdy/spdy_session.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