OLD | NEW |
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/basictypes.h" | 7 #include "base/basictypes.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/memory/linked_ptr.h" | 9 #include "base/memory/linked_ptr.h" |
10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
239 streams_abandoned_count_(0), | 239 streams_abandoned_count_(0), |
240 frames_received_(0), | 240 frames_received_(0), |
241 bytes_received_(0), | 241 bytes_received_(0), |
242 sent_settings_(false), | 242 sent_settings_(false), |
243 received_settings_(false), | 243 received_settings_(false), |
244 stalled_streams_(0), | 244 stalled_streams_(0), |
245 initial_send_window_size_(spdy::kSpdyStreamInitialWindowSize), | 245 initial_send_window_size_(spdy::kSpdyStreamInitialWindowSize), |
246 initial_recv_window_size_(spdy::kSpdyStreamInitialWindowSize), | 246 initial_recv_window_size_(spdy::kSpdyStreamInitialWindowSize), |
247 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SPDY_SESSION)) { | 247 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SPDY_SESSION)) { |
248 DCHECK(HttpStreamFactory::spdy_enabled()); | 248 DCHECK(HttpStreamFactory::spdy_enabled()); |
| 249 // TODO(jtl): Do we need to set kMaxSpdyFrameChunkSize here based on which |
| 250 // transport protocol we're using? |
249 net_log_.BeginEvent( | 251 net_log_.BeginEvent( |
250 NetLog::TYPE_SPDY_SESSION, | 252 NetLog::TYPE_SPDY_SESSION, |
251 make_scoped_refptr( | 253 make_scoped_refptr( |
252 new NetLogSpdySessionParameter(host_port_proxy_pair_))); | 254 new NetLogSpdySessionParameter(host_port_proxy_pair_))); |
253 | 255 |
254 // TODO(mbelshe): consider randomization of the stream_hi_water_mark. | 256 // TODO(mbelshe): consider randomization of the stream_hi_water_mark. |
255 | 257 |
256 spdy_framer_.set_visitor(this); | 258 spdy_framer_.set_visitor(this); |
257 | 259 |
258 SendSettings(); | 260 SendSettings(); |
(...skipping 498 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
757 LOG(ERROR) << "SPDY Compression failure"; | 759 LOG(ERROR) << "SPDY Compression failure"; |
758 CloseSessionOnError(net::ERR_SPDY_PROTOCOL_ERROR, true); | 760 CloseSessionOnError(net::ERR_SPDY_PROTOCOL_ERROR, true); |
759 return; | 761 return; |
760 } | 762 } |
761 | 763 |
762 size = compressed_frame->length() + spdy::SpdyFrame::size(); | 764 size = compressed_frame->length() + spdy::SpdyFrame::size(); |
763 | 765 |
764 DCHECK_GT(size, 0u); | 766 DCHECK_GT(size, 0u); |
765 | 767 |
766 // TODO(mbelshe): We have too much copying of data here. | 768 // TODO(mbelshe): We have too much copying of data here. |
767 IOBufferWithSize* buffer = new IOBufferWithSize(size); | 769 // TODO(jtl): Why is this "WithSize"? |
| 770 IOBuffer* buffer = new IOBufferWithSize(size); |
768 memcpy(buffer->data(), compressed_frame->data(), size); | 771 memcpy(buffer->data(), compressed_frame->data(), size); |
769 | 772 |
770 // Attempt to send the frame. | 773 // Attempt to send the frame. |
771 in_flight_write_ = SpdyIOBuffer(buffer, size, 0, next_buffer.stream()); | 774 in_flight_write_ = SpdyIOBuffer(buffer, size, 0, next_buffer.stream()); |
772 } else { | 775 } else { |
773 size = uncompressed_frame.length() + spdy::SpdyFrame::size(); | 776 size = uncompressed_frame.length() + spdy::SpdyFrame::size(); |
774 in_flight_write_ = next_buffer; | 777 in_flight_write_ = next_buffer; |
775 } | 778 } |
| 779 // SCTP stream ID assignment is delayed until now, rather than done in |
| 780 // QueueFrame, to be sure the association (connection) has been |
| 781 // established. SCTP stream ID numbers can't be assigned until |
| 782 // g_max_sctp_streams is set, and that can't happen until the association |
| 783 // is established. |
| 784 // TODO(jtl): In order to support piggy-backing DATA on the COOKIE_ECHO, |
| 785 // as is allowed in FreeBSD and Mac OS X, we need to find a way to allow |
| 786 // at least sctp stream ID 1 to be used prior to g_max_sctp_streams being |
| 787 // set. |
| 788 // |
| 789 if (using_sctp()) { |
| 790 spdy::SpdyFrame frame(in_flight_write_.buffer()->data(), false); |
| 791 in_flight_write_.set_sctp_stream_id(GetSctpStreamID(frame)); |
| 792 } |
776 } else { | 793 } else { |
777 DCHECK(in_flight_write_.buffer()->BytesRemaining()); | 794 DCHECK(in_flight_write_.buffer()->BytesRemaining()); |
778 } | 795 } |
779 | 796 |
780 write_pending_ = true; | 797 write_pending_ = true; |
| 798 |
781 int rv = connection_->socket()->Write(in_flight_write_.buffer(), | 799 int rv = connection_->socket()->Write(in_flight_write_.buffer(), |
782 in_flight_write_.buffer()->BytesRemaining(), &write_callback_); | 800 in_flight_write_.buffer()->BytesRemaining(), &write_callback_); |
783 if (rv == net::ERR_IO_PENDING) | 801 if (rv == net::ERR_IO_PENDING) |
784 break; | 802 break; |
785 | 803 |
786 // We sent the frame successfully. | 804 // We sent the frame successfully. |
787 OnWriteComplete(rv); | 805 OnWriteComplete(rv); |
788 | 806 |
789 // TODO(mbelshe): Test this error case. Maybe we should mark the socket | 807 // TODO(mbelshe): Test this error case. Maybe we should mark the socket |
790 // as in an error state. | 808 // as in an error state. |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
829 } | 847 } |
830 | 848 |
831 int SpdySession::GetNewStreamId() { | 849 int SpdySession::GetNewStreamId() { |
832 int id = stream_hi_water_mark_; | 850 int id = stream_hi_water_mark_; |
833 stream_hi_water_mark_ += 2; | 851 stream_hi_water_mark_ += 2; |
834 if (stream_hi_water_mark_ > 0x7fff) | 852 if (stream_hi_water_mark_ > 0x7fff) |
835 stream_hi_water_mark_ = 1; | 853 stream_hi_water_mark_ = 1; |
836 return id; | 854 return id; |
837 } | 855 } |
838 | 856 |
| 857 uint16 SpdySession::GetSctpStreamID(const spdy::SpdyFrame& frame) { |
| 858 uint32 stream_id = 0; |
| 859 if (!frame.is_control_frame()) { |
| 860 stream_id = reinterpret_cast<const spdy::SpdyDataFrame&>(frame).stream_id(); |
| 861 } else if (!using_sctp_control_stream()) { |
| 862 spdy::SpdyControlType type = |
| 863 reinterpret_cast<const spdy::SpdyControlFrame&>(frame).type(); |
| 864 // n.b. When not using an SCTP control stream, SETTINGS, NOOP, PING |
| 865 // and GOAWAY control frames are still sent on SCTP stream 0 because |
| 866 // they are not associated with a specific SPDY stream. |
| 867 switch (type) { |
| 868 case spdy::SYN_STREAM: |
| 869 stream_id = static_cast<const spdy::SpdySynStreamControlFrame&> |
| 870 (frame).stream_id(); |
| 871 break; |
| 872 case spdy::SYN_REPLY: |
| 873 stream_id = static_cast<const spdy::SpdySynReplyControlFrame&> |
| 874 (frame).stream_id(); |
| 875 break; |
| 876 case spdy::RST_STREAM: |
| 877 stream_id = static_cast<const spdy::SpdyRstStreamControlFrame&> |
| 878 (frame).stream_id(); |
| 879 break; |
| 880 case spdy::HEADERS: |
| 881 stream_id = static_cast<const spdy::SpdyHeadersControlFrame&> |
| 882 (frame).stream_id(); |
| 883 break; |
| 884 case spdy::WINDOW_UPDATE: |
| 885 stream_id = static_cast<const spdy::SpdyWindowUpdateControlFrame&> |
| 886 (frame).stream_id(); |
| 887 break; |
| 888 default: |
| 889 break; |
| 890 } |
| 891 } |
| 892 |
| 893 return stream_id ? MapSpdyToSctp(stream_id) : 0; |
| 894 } |
| 895 |
839 void SpdySession::QueueFrame(spdy::SpdyFrame* frame, | 896 void SpdySession::QueueFrame(spdy::SpdyFrame* frame, |
840 spdy::SpdyPriority priority, | 897 spdy::SpdyPriority priority, |
841 SpdyStream* stream) { | 898 SpdyStream* stream) { |
842 int length = spdy::SpdyFrame::size() + frame->length(); | 899 int length = spdy::SpdyFrame::size() + frame->length(); |
843 IOBuffer* buffer = new IOBuffer(length); | 900 IOBuffer* buffer; |
| 901 buffer = new IOBuffer(length); |
844 memcpy(buffer->data(), frame->data(), length); | 902 memcpy(buffer->data(), frame->data(), length); |
| 903 // can't assign IOBuffer::sctp_stream_id_ here because the association may not |
| 904 // be established yet. See comments in SpdySession::WriteSocket() |
845 queue_.push(SpdyIOBuffer(buffer, length, priority, stream)); | 905 queue_.push(SpdyIOBuffer(buffer, length, priority, stream)); |
846 | 906 |
847 WriteSocketLater(); | 907 WriteSocketLater(); |
848 } | 908 } |
849 | 909 |
850 void SpdySession::CloseSessionOnError(net::Error err, bool remove_from_pool) { | 910 void SpdySession::CloseSessionOnError(net::Error err, bool remove_from_pool) { |
851 // Closing all streams can have a side-effect of dropping the last reference | 911 // Closing all streams can have a side-effect of dropping the last reference |
852 // to |this|. Hold a reference through this function. | 912 // to |this|. Hold a reference through this function. |
853 scoped_refptr<SpdySession> self(this); | 913 scoped_refptr<SpdySession> self(this); |
854 | 914 |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1117 spdy::SpdyStreamId stream_id = frame.stream_id(); | 1177 spdy::SpdyStreamId stream_id = frame.stream_id(); |
1118 | 1178 |
1119 bool valid_stream = IsStreamActive(stream_id); | 1179 bool valid_stream = IsStreamActive(stream_id); |
1120 if (!valid_stream) { | 1180 if (!valid_stream) { |
1121 // NOTE: it may just be that the stream was cancelled. | 1181 // NOTE: it may just be that the stream was cancelled. |
1122 LOG(WARNING) << "Received SYN_REPLY for invalid stream " << stream_id; | 1182 LOG(WARNING) << "Received SYN_REPLY for invalid stream " << stream_id; |
1123 return; | 1183 return; |
1124 } | 1184 } |
1125 | 1185 |
1126 scoped_refptr<SpdyStream> stream = active_streams_[stream_id]; | 1186 scoped_refptr<SpdyStream> stream = active_streams_[stream_id]; |
| 1187 if (using_sctp() && using_sctp_control_stream()) |
| 1188 stream->set_syn_reply_received(); |
1127 CHECK_EQ(stream->stream_id(), stream_id); | 1189 CHECK_EQ(stream->stream_id(), stream_id); |
1128 CHECK(!stream->cancelled()); | 1190 CHECK(!stream->cancelled()); |
1129 | 1191 |
1130 if (stream->response_received()) { | 1192 if (stream->response_received()) { |
1131 LOG(WARNING) << "Received duplicate SYN_REPLY for stream " << stream_id; | 1193 LOG(WARNING) << "Received duplicate SYN_REPLY for stream " << stream_id; |
1132 CloseStream(stream->stream_id(), ERR_SPDY_PROTOCOL_ERROR); | 1194 CloseStream(stream->stream_id(), ERR_SPDY_PROTOCOL_ERROR); |
1133 return; | 1195 return; |
1134 } | 1196 } |
1135 stream->set_response_received(); | 1197 stream->set_response_received(); |
1136 | 1198 |
1137 if (net_log().IsLoggingAllEvents()) { | 1199 if (net_log().IsLoggingAllEvents()) { |
1138 net_log().AddEvent( | 1200 net_log().AddEvent( |
1139 NetLog::TYPE_SPDY_SESSION_SYN_REPLY, | 1201 NetLog::TYPE_SPDY_SESSION_SYN_REPLY, |
1140 make_scoped_refptr(new NetLogSpdySynParameter( | 1202 make_scoped_refptr(new NetLogSpdySynParameter( |
1141 headers, static_cast<spdy::SpdyControlFlags>(frame.flags()), | 1203 headers, static_cast<spdy::SpdyControlFlags>(frame.flags()), |
1142 stream_id, 0))); | 1204 stream_id, 0))); |
1143 } | 1205 } |
1144 | 1206 |
1145 Respond(*headers, stream); | 1207 Respond(*headers, stream); |
| 1208 |
| 1209 // When using SCTP with a control stream, loss can result in the SYN_REPLY |
| 1210 // arriving after all the data. In this case close_pending() will be true |
| 1211 // and we need to call OnDataReceived to shutdown the metrics and close the |
| 1212 // stream. |
| 1213 if (using_sctp() && using_sctp_control_stream() && |
| 1214 stream->close_pending()) |
| 1215 stream->OnDataReceived(NULL, 0); |
1146 } | 1216 } |
1147 | 1217 |
1148 void SpdySession::OnHeaders(const spdy::SpdyHeadersControlFrame& frame, | 1218 void SpdySession::OnHeaders(const spdy::SpdyHeadersControlFrame& frame, |
1149 const linked_ptr<spdy::SpdyHeaderBlock>& headers) { | 1219 const linked_ptr<spdy::SpdyHeaderBlock>& headers) { |
1150 spdy::SpdyStreamId stream_id = frame.stream_id(); | 1220 spdy::SpdyStreamId stream_id = frame.stream_id(); |
1151 | 1221 |
1152 bool valid_stream = IsStreamActive(stream_id); | 1222 bool valid_stream = IsStreamActive(stream_id); |
1153 if (!valid_stream) { | 1223 if (!valid_stream) { |
1154 // NOTE: it may just be that the stream was cancelled. | 1224 // NOTE: it may just be that the stream was cancelled. |
1155 LOG(WARNING) << "Received HEADERS for invalid stream " << stream_id; | 1225 LOG(WARNING) << "Received HEADERS for invalid stream " << stream_id; |
(...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1497 if (it == pending_callback_map_.end()) | 1567 if (it == pending_callback_map_.end()) |
1498 return; | 1568 return; |
1499 | 1569 |
1500 CompletionCallback* callback = it->second.callback; | 1570 CompletionCallback* callback = it->second.callback; |
1501 int result = it->second.result; | 1571 int result = it->second.result; |
1502 pending_callback_map_.erase(it); | 1572 pending_callback_map_.erase(it); |
1503 callback->Run(result); | 1573 callback->Run(result); |
1504 } | 1574 } |
1505 | 1575 |
1506 } // namespace net | 1576 } // namespace net |
OLD | NEW |