Index: net/spdy/spdy_session.cc |
=================================================================== |
--- net/spdy/spdy_session.cc (revision 80449) |
+++ net/spdy/spdy_session.cc (working copy) |
@@ -246,6 +246,8 @@ |
initial_recv_window_size_(spdy::kSpdyStreamInitialWindowSize), |
net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SPDY_SESSION)) { |
DCHECK(HttpStreamFactory::spdy_enabled()); |
+ // TODO(jtl): Do we need to set kMaxSpdyFrameChunkSize here based on which |
+ // transport protocol we're using? |
net_log_.BeginEvent( |
NetLog::TYPE_SPDY_SESSION, |
make_scoped_refptr( |
@@ -764,7 +766,8 @@ |
DCHECK_GT(size, 0u); |
// TODO(mbelshe): We have too much copying of data here. |
- IOBufferWithSize* buffer = new IOBufferWithSize(size); |
+ // TODO(jtl): Why is this "WithSize"? |
+ IOBuffer* buffer = new IOBufferWithSize(size); |
memcpy(buffer->data(), compressed_frame->data(), size); |
// Attempt to send the frame. |
@@ -773,11 +776,26 @@ |
size = uncompressed_frame.length() + spdy::SpdyFrame::size(); |
in_flight_write_ = next_buffer; |
} |
+ // SCTP stream ID assignment is delayed until now, rather than done in |
+ // QueueFrame, to be sure the association (connection) has been |
+ // established. SCTP stream ID numbers can't be assigned until |
+ // g_max_sctp_streams is set, and that can't happen until the association |
+ // is established. |
+ // TODO(jtl): In order to support piggy-backing DATA on the COOKIE_ECHO, |
+ // as is allowed in FreeBSD and Mac OS X, we need to find a way to allow |
+ // at least sctp stream ID 1 to be used prior to g_max_sctp_streams being |
+ // set. |
+ // |
+ if (using_sctp()) { |
+ spdy::SpdyFrame frame(in_flight_write_.buffer()->data(), false); |
+ in_flight_write_.set_sctp_stream_id(GetSctpStreamID(frame)); |
+ } |
} else { |
DCHECK(in_flight_write_.buffer()->BytesRemaining()); |
} |
write_pending_ = true; |
+ |
int rv = connection_->socket()->Write(in_flight_write_.buffer(), |
in_flight_write_.buffer()->BytesRemaining(), &write_callback_); |
if (rv == net::ERR_IO_PENDING) |
@@ -836,12 +854,54 @@ |
return id; |
} |
+uint16 SpdySession::GetSctpStreamID(const spdy::SpdyFrame& frame) { |
+ uint32 stream_id = 0; |
+ if (!frame.is_control_frame()) { |
+ stream_id = reinterpret_cast<const spdy::SpdyDataFrame&>(frame).stream_id(); |
+ } else if (!using_sctp_control_stream()) { |
+ spdy::SpdyControlType type = |
+ reinterpret_cast<const spdy::SpdyControlFrame&>(frame).type(); |
+ // n.b. When not using an SCTP control stream, SETTINGS, NOOP, PING |
+ // and GOAWAY control frames are still sent on SCTP stream 0 because |
+ // they are not associated with a specific SPDY stream. |
+ switch (type) { |
+ case spdy::SYN_STREAM: |
+ stream_id = static_cast<const spdy::SpdySynStreamControlFrame&> |
+ (frame).stream_id(); |
+ break; |
+ case spdy::SYN_REPLY: |
+ stream_id = static_cast<const spdy::SpdySynReplyControlFrame&> |
+ (frame).stream_id(); |
+ break; |
+ case spdy::RST_STREAM: |
+ stream_id = static_cast<const spdy::SpdyRstStreamControlFrame&> |
+ (frame).stream_id(); |
+ break; |
+ case spdy::HEADERS: |
+ stream_id = static_cast<const spdy::SpdyHeadersControlFrame&> |
+ (frame).stream_id(); |
+ break; |
+ case spdy::WINDOW_UPDATE: |
+ stream_id = static_cast<const spdy::SpdyWindowUpdateControlFrame&> |
+ (frame).stream_id(); |
+ break; |
+ default: |
+ break; |
+ } |
+ } |
+ |
+ return stream_id ? MapSpdyToSctp(stream_id) : 0; |
+} |
+ |
void SpdySession::QueueFrame(spdy::SpdyFrame* frame, |
spdy::SpdyPriority priority, |
SpdyStream* stream) { |
int length = spdy::SpdyFrame::size() + frame->length(); |
- IOBuffer* buffer = new IOBuffer(length); |
+ IOBuffer* buffer; |
+ buffer = new IOBuffer(length); |
memcpy(buffer->data(), frame->data(), length); |
+ // can't assign IOBuffer::sctp_stream_id_ here because the association may not |
+ // be established yet. See comments in SpdySession::WriteSocket() |
queue_.push(SpdyIOBuffer(buffer, length, priority, stream)); |
WriteSocketLater(); |
@@ -1124,6 +1184,8 @@ |
} |
scoped_refptr<SpdyStream> stream = active_streams_[stream_id]; |
+ if (using_sctp() && using_sctp_control_stream()) |
+ stream->set_syn_reply_received(); |
CHECK_EQ(stream->stream_id(), stream_id); |
CHECK(!stream->cancelled()); |
@@ -1143,6 +1205,14 @@ |
} |
Respond(*headers, stream); |
+ |
+ // When using SCTP with a control stream, loss can result in the SYN_REPLY |
+ // arriving after all the data. In this case close_pending() will be true |
+ // and we need to call OnDataReceived to shutdown the metrics and close the |
+ // stream. |
+ if (using_sctp() && using_sctp_control_stream() && |
+ stream->close_pending()) |
+ stream->OnDataReceived(NULL, 0); |
} |
void SpdySession::OnHeaders(const spdy::SpdyHeadersControlFrame& frame, |