OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "net/quic/quic_session.h" | |
6 | |
7 #include "net/quic/quic_connection.h" | |
8 | |
9 using base::StringPiece; | |
10 using base::hash_map; | |
11 using base::hash_set; | |
12 using std::vector; | |
13 | |
14 namespace net { | |
15 | |
16 QuicSession::QuicSession(QuicConnection* connection, bool is_server) | |
17 : connection_(connection), | |
18 max_open_streams_(kDefaultMaxStreamsPerConnection), | |
19 next_stream_id_(is_server ? 2 : 3), | |
20 is_server_(is_server), | |
21 largest_peer_created_stream_id_(0) { | |
22 connection_->set_visitor(this); | |
23 } | |
24 | |
25 QuicSession::~QuicSession() { | |
26 } | |
27 | |
28 bool QuicSession::OnPacket(const IPEndPoint& self_address, | |
29 const IPEndPoint& peer_address, | |
30 const QuicPacketHeader& header, | |
31 const vector<QuicStreamFrame>& frames) { | |
32 if (header.guid != connection()->guid()) { | |
33 DLOG(INFO) << "Got packet header for invalid GUID: " << header.guid; | |
34 return false; | |
35 } | |
36 for (size_t i = 0; i < frames.size(); ++i) { | |
37 // TODO(rch) deal with the error case of stream id 0 | |
38 if (IsClosedStream(frames[i].stream_id)) continue; | |
39 | |
40 ReliableQuicStream* stream = GetStream(frames[i].stream_id); | |
41 if (stream == NULL) return false; | |
42 if (!stream->WillAcceptStreamFrame(frames[i])) return false; | |
43 | |
44 // TODO(alyssar) check against existing connection address: if changed, make | |
45 // sure we update the connection. | |
46 } | |
47 | |
48 for (size_t i = 0; i < frames.size(); ++i) { | |
49 ReliableQuicStream* stream = GetStream(frames[i].stream_id); | |
50 if (stream) { | |
51 stream->OnStreamFrame(frames[i]); | |
52 } | |
53 } | |
54 return true; | |
55 } | |
56 | |
57 void QuicSession::OnRstStream(const QuicRstStreamFrame& frame) { | |
58 ReliableQuicStream* stream = GetStream(frame.stream_id); | |
59 if (!stream) { | |
60 return; // Errors are handled by GetStream. | |
61 } | |
62 stream->OnStreamReset(frame.error_code, frame.offset); | |
63 } | |
64 | |
65 void QuicSession::ConnectionClose(QuicErrorCode error, bool from_peer) { | |
66 while (stream_map_.size() != 0) { | |
67 ReliableStreamMap::iterator it = stream_map_.begin(); | |
68 QuicStreamId id = it->first; | |
69 it->second->ConnectionClose(error, from_peer); | |
70 // The stream should call CloseStream as part of ConnectionClose. | |
71 if (stream_map_.find(id) != stream_map_.end()) { | |
72 LOG(DFATAL) << "Stream failed to close under ConnectionClose"; | |
73 CloseStream(id); | |
74 } | |
75 } | |
76 } | |
77 | |
78 int QuicSession::WriteData(QuicStreamId id, StringPiece data, | |
79 QuicStreamOffset offset, bool fin) { | |
80 return connection_->SendStreamData(id, data, offset, fin, NULL); | |
81 } | |
82 | |
83 void QuicSession::SendRstStream(QuicStreamId id, | |
84 QuicErrorCode error, | |
85 QuicStreamOffset offset) { | |
86 connection_->SendRstStream(id, error, offset); | |
87 CloseStream(id); | |
88 } | |
89 | |
90 void QuicSession::CloseStream(QuicStreamId stream_id) { | |
91 DLOG(INFO) << "Closing stream " << stream_id; | |
92 | |
93 ReliableStreamMap::iterator it = stream_map_.find(stream_id); | |
94 if (it == stream_map_.end()) { | |
95 DLOG(INFO) << "Stream is already closed: " << stream_id; | |
96 return; | |
97 } | |
98 stream_map_.erase(it); | |
99 } | |
100 | |
101 bool QuicSession::IsHandshakeComplete() { | |
102 return GetCryptoStream()->handshake_complete(); | |
103 } | |
104 | |
105 void QuicSession::ActivateStream(ReliableQuicStream* stream) { | |
106 LOG(INFO) << "num_streams: " << stream_map_.size() | |
107 << ". activating " << stream->id(); | |
108 DCHECK(stream_map_.count(stream->id()) == 0); | |
109 stream_map_[stream->id()] = stream; | |
110 } | |
111 | |
112 QuicStreamId QuicSession::GetNextStreamId() { | |
113 QuicStreamId id = next_stream_id_; | |
114 next_stream_id_ += 2; | |
115 return id; | |
116 } | |
117 | |
118 ReliableQuicStream* QuicSession::GetStream(const QuicStreamId stream_id) { | |
119 if (stream_id == kCryptoStreamId) { | |
120 return GetCryptoStream(); | |
121 } | |
122 | |
123 ReliableStreamMap::iterator it = stream_map_.find(stream_id); | |
124 if (it != stream_map_.end()) { | |
125 return it->second; | |
126 } | |
127 | |
128 if (stream_id % 2 == next_stream_id_ % 2) { | |
129 // We've received a frame for a locally-created stream that is not | |
130 // currently active. This is an error. | |
131 connection()->SendConnectionClose(QUIC_PACKET_FOR_NONEXISTENT_STREAM); | |
132 return NULL; | |
133 } | |
134 | |
135 return GetIncomingReliableStream(stream_id); | |
136 } | |
137 | |
138 ReliableQuicStream* QuicSession::GetIncomingReliableStream( | |
139 QuicStreamId stream_id) { | |
140 if (IsClosedStream(stream_id)) { | |
141 return NULL; | |
142 } | |
143 | |
144 implicitly_created_streams_.erase(stream_id); | |
145 if (stream_id > largest_peer_created_stream_id_) { | |
146 // TODO(rch) add unit test for this | |
147 if (stream_id - largest_peer_created_stream_id_ > kMaxStreamIdDelta) { | |
148 connection()->SendConnectionClose(QUIC_INVALID_STREAM_ID); | |
149 return NULL; | |
150 } | |
151 if (largest_peer_created_stream_id_ != 0) { | |
152 for (QuicStreamId id = largest_peer_created_stream_id_ + 2; | |
153 id < stream_id; | |
154 id += 2) { | |
155 implicitly_created_streams_.insert(id); | |
156 } | |
157 } | |
158 largest_peer_created_stream_id_ = stream_id; | |
159 } | |
160 ReliableQuicStream* stream = CreateIncomingReliableStream(stream_id); | |
161 if (stream == NULL) { | |
162 connection()->SendConnectionClose(QUIC_TOO_MANY_OPEN_STREAMS); | |
163 return NULL; | |
164 } | |
165 ActivateStream(stream); | |
166 return stream; | |
167 } | |
168 | |
169 bool QuicSession::IsClosedStream(QuicStreamId id) { | |
170 DCHECK_NE(0u, id); | |
171 if (id == kCryptoStreamId) { | |
172 return false; | |
173 } | |
174 if (stream_map_.count(id) != 0) { | |
175 // Stream is active | |
176 return false; | |
177 } | |
178 if (id % 2 == next_stream_id_ % 2) { | |
179 // If the stream was locally initiated we strictly in-order creation. | |
180 // If the id is in the range of created streams and it's not active, it | |
181 // must have been closed. | |
182 return id < next_stream_id_; | |
183 } else { | |
184 // For peer created streams, we also need to consider | |
185 // implicitly created streams. | |
186 return id <= largest_peer_created_stream_id_ && | |
187 implicitly_created_streams_.count(id) == 0; | |
188 } | |
189 } | |
190 | |
191 size_t QuicSession::GetNumOpenStreams() { | |
192 return stream_map_.size() + implicitly_created_streams_.size(); | |
193 } | |
194 | |
195 } // namespace net | |
OLD | NEW |