OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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/quic/quic_connection.h" | 5 #include "net/quic/quic_connection.h" |
6 | 6 |
7 #include <string.h> | 7 #include <string.h> |
8 #include <sys/types.h> | 8 #include <sys/types.h> |
9 #include <algorithm> | 9 #include <algorithm> |
10 #include <iterator> | 10 #include <iterator> |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
197 uint32 max_flow_control_receive_window_bytes) | 197 uint32 max_flow_control_receive_window_bytes) |
198 : framer_(supported_versions, helper->GetClock()->ApproximateNow(), | 198 : framer_(supported_versions, helper->GetClock()->ApproximateNow(), |
199 is_server), | 199 is_server), |
200 helper_(helper), | 200 helper_(helper), |
201 writer_(writer), | 201 writer_(writer), |
202 encryption_level_(ENCRYPTION_NONE), | 202 encryption_level_(ENCRYPTION_NONE), |
203 clock_(helper->GetClock()), | 203 clock_(helper->GetClock()), |
204 random_generator_(helper->GetRandomGenerator()), | 204 random_generator_(helper->GetRandomGenerator()), |
205 connection_id_(connection_id), | 205 connection_id_(connection_id), |
206 peer_address_(address), | 206 peer_address_(address), |
| 207 migrating_peer_port_(0), |
207 last_packet_revived_(false), | 208 last_packet_revived_(false), |
208 last_size_(0), | 209 last_size_(0), |
209 last_decrypted_packet_level_(ENCRYPTION_NONE), | 210 last_decrypted_packet_level_(ENCRYPTION_NONE), |
210 largest_seen_packet_with_ack_(0), | 211 largest_seen_packet_with_ack_(0), |
211 largest_seen_packet_with_stop_waiting_(0), | 212 largest_seen_packet_with_stop_waiting_(0), |
212 pending_version_negotiation_packet_(false), | 213 pending_version_negotiation_packet_(false), |
213 received_packet_manager_(kTCP, &stats_), | 214 received_packet_manager_(kTCP, &stats_), |
214 ack_queued_(false), | 215 ack_queued_(false), |
215 stop_waiting_count_(0), | 216 stop_waiting_count_(0), |
216 ack_alarm_(helper->CreateAlarm(new AckAlarm(this))), | 217 ack_alarm_(helper->CreateAlarm(new AckAlarm(this))), |
(...skipping 10 matching lines...) Expand all Loading... |
227 overall_connection_timeout_(QuicTime::Delta::Infinite()), | 228 overall_connection_timeout_(QuicTime::Delta::Infinite()), |
228 time_of_last_received_packet_(clock_->ApproximateNow()), | 229 time_of_last_received_packet_(clock_->ApproximateNow()), |
229 time_of_last_sent_new_packet_(clock_->ApproximateNow()), | 230 time_of_last_sent_new_packet_(clock_->ApproximateNow()), |
230 sequence_number_of_last_sent_packet_(0), | 231 sequence_number_of_last_sent_packet_(0), |
231 sent_packet_manager_( | 232 sent_packet_manager_( |
232 is_server, clock_, &stats_, kTCP, | 233 is_server, clock_, &stats_, kTCP, |
233 FLAGS_quic_use_time_loss_detection ? kTime : kNack), | 234 FLAGS_quic_use_time_loss_detection ? kTime : kNack), |
234 version_negotiation_state_(START_NEGOTIATION), | 235 version_negotiation_state_(START_NEGOTIATION), |
235 is_server_(is_server), | 236 is_server_(is_server), |
236 connected_(true), | 237 connected_(true), |
237 address_migrating_(false), | 238 peer_ip_changed_(false), |
| 239 peer_port_changed_(false), |
| 240 self_ip_changed_(false), |
| 241 self_port_changed_(false), |
238 max_flow_control_receive_window_bytes_( | 242 max_flow_control_receive_window_bytes_( |
239 max_flow_control_receive_window_bytes) { | 243 max_flow_control_receive_window_bytes) { |
240 if (max_flow_control_receive_window_bytes_ < kDefaultFlowControlSendWindow) { | 244 if (max_flow_control_receive_window_bytes_ < kDefaultFlowControlSendWindow) { |
241 DLOG(ERROR) << "Initial receive window (" | 245 DLOG(ERROR) << "Initial receive window (" |
242 << max_flow_control_receive_window_bytes_ | 246 << max_flow_control_receive_window_bytes_ |
243 << ") cannot be set lower than default (" | 247 << ") cannot be set lower than default (" |
244 << kDefaultFlowControlSendWindow << ")."; | 248 << kDefaultFlowControlSendWindow << ")."; |
245 max_flow_control_receive_window_bytes_ = kDefaultFlowControlSendWindow; | 249 max_flow_control_receive_window_bytes_ = kDefaultFlowControlSendWindow; |
246 } | 250 } |
247 | 251 |
(...skipping 850 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1098 const QuicEncryptedPacket& packet) { | 1102 const QuicEncryptedPacket& packet) { |
1099 if (!connected_) { | 1103 if (!connected_) { |
1100 return; | 1104 return; |
1101 } | 1105 } |
1102 if (debug_visitor_) { | 1106 if (debug_visitor_) { |
1103 debug_visitor_->OnPacketReceived(self_address, peer_address, packet); | 1107 debug_visitor_->OnPacketReceived(self_address, peer_address, packet); |
1104 } | 1108 } |
1105 last_packet_revived_ = false; | 1109 last_packet_revived_ = false; |
1106 last_size_ = packet.length(); | 1110 last_size_ = packet.length(); |
1107 | 1111 |
1108 address_migrating_ = false; | 1112 CheckForAddressMigration(self_address, peer_address); |
1109 | |
1110 if (peer_address_.address().empty()) { | |
1111 peer_address_ = peer_address; | |
1112 } | |
1113 if (self_address_.address().empty()) { | |
1114 self_address_ = self_address; | |
1115 } | |
1116 | |
1117 if (!(peer_address == peer_address_ && self_address == self_address_)) { | |
1118 address_migrating_ = true; | |
1119 } | |
1120 | 1113 |
1121 stats_.bytes_received += packet.length(); | 1114 stats_.bytes_received += packet.length(); |
1122 ++stats_.packets_received; | 1115 ++stats_.packets_received; |
1123 | 1116 |
1124 if (!framer_.ProcessPacket(packet)) { | 1117 if (!framer_.ProcessPacket(packet)) { |
1125 // If we are unable to decrypt this packet, it might be | 1118 // If we are unable to decrypt this packet, it might be |
1126 // because the CHLO or SHLO packet was lost. | 1119 // because the CHLO or SHLO packet was lost. |
1127 if (encryption_level_ != ENCRYPTION_FORWARD_SECURE && | 1120 if (encryption_level_ != ENCRYPTION_FORWARD_SECURE && |
1128 framer_.error() == QUIC_DECRYPTION_FAILURE && | 1121 framer_.error() == QUIC_DECRYPTION_FAILURE && |
1129 undecryptable_packets_.size() < kMaxUndecryptablePackets) { | 1122 undecryptable_packets_.size() < kMaxUndecryptablePackets) { |
1130 QueueUndecryptablePacket(packet); | 1123 QueueUndecryptablePacket(packet); |
1131 } | 1124 } |
1132 DVLOG(1) << ENDPOINT << "Unable to process packet. Last packet processed: " | 1125 DVLOG(1) << ENDPOINT << "Unable to process packet. Last packet processed: " |
1133 << last_header_.packet_sequence_number; | 1126 << last_header_.packet_sequence_number; |
1134 return; | 1127 return; |
1135 } | 1128 } |
1136 | 1129 |
1137 ++stats_.packets_processed; | 1130 ++stats_.packets_processed; |
1138 MaybeProcessUndecryptablePackets(); | 1131 MaybeProcessUndecryptablePackets(); |
1139 MaybeProcessRevivedPacket(); | 1132 MaybeProcessRevivedPacket(); |
1140 MaybeSendInResponseToPacket(); | 1133 MaybeSendInResponseToPacket(); |
1141 SetPingAlarm(); | 1134 SetPingAlarm(); |
1142 } | 1135 } |
1143 | 1136 |
| 1137 void QuicConnection::CheckForAddressMigration( |
| 1138 const IPEndPoint& self_address, const IPEndPoint& peer_address) { |
| 1139 peer_ip_changed_ = false; |
| 1140 peer_port_changed_ = false; |
| 1141 self_ip_changed_ = false; |
| 1142 self_port_changed_ = false; |
| 1143 |
| 1144 if (peer_address_.address().empty()) { |
| 1145 peer_address_ = peer_address; |
| 1146 } |
| 1147 if (self_address_.address().empty()) { |
| 1148 self_address_ = self_address; |
| 1149 } |
| 1150 |
| 1151 if (!peer_address.address().empty() && !peer_address_.address().empty()) { |
| 1152 peer_ip_changed_ = (peer_address.address() != peer_address_.address()); |
| 1153 peer_port_changed_ = (peer_address.port() != peer_address_.port()); |
| 1154 |
| 1155 // Store in case we want to migrate connection in ProcessValidatedPacket. |
| 1156 migrating_peer_port_ = peer_address.port(); |
| 1157 } |
| 1158 |
| 1159 if (!self_address.address().empty() && !self_address_.address().empty()) { |
| 1160 self_ip_changed_ = (self_address.address() != self_address_.address()); |
| 1161 self_port_changed_ = (self_address.port() != self_address_.port()); |
| 1162 } |
| 1163 } |
| 1164 |
1144 void QuicConnection::OnCanWrite() { | 1165 void QuicConnection::OnCanWrite() { |
1145 DCHECK(!writer_->IsWriteBlocked()); | 1166 DCHECK(!writer_->IsWriteBlocked()); |
1146 | 1167 |
1147 WriteQueuedPackets(); | 1168 WriteQueuedPackets(); |
1148 WritePendingRetransmissions(); | 1169 WritePendingRetransmissions(); |
1149 | 1170 |
1150 IsHandshake pending_handshake = visitor_->HasPendingHandshake() ? | |
1151 IS_HANDSHAKE : NOT_HANDSHAKE; | |
1152 // Sending queued packets may have caused the socket to become write blocked, | 1171 // Sending queued packets may have caused the socket to become write blocked, |
1153 // or the congestion manager to prohibit sending. If we've sent everything | 1172 // or the congestion manager to prohibit sending. If we've sent everything |
1154 // we had queued and we're still not blocked, let the visitor know it can | 1173 // we had queued and we're still not blocked, let the visitor know it can |
1155 // write more. | 1174 // write more. |
1156 if (!CanWrite(NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, | 1175 if (!CanWrite(NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA)) { |
1157 pending_handshake)) { | |
1158 return; | 1176 return; |
1159 } | 1177 } |
1160 | 1178 |
1161 { // Limit the scope of the bundler. | 1179 { // Limit the scope of the bundler. |
1162 // Set |include_ack| to false in bundler; ack inclusion happens elsewhere. | 1180 // Set |include_ack| to false in bundler; ack inclusion happens elsewhere. |
1163 ScopedPacketBundler bundler(this, NO_ACK); | 1181 ScopedPacketBundler bundler(this, NO_ACK); |
1164 visitor_->OnCanWrite(); | 1182 visitor_->OnCanWrite(); |
1165 } | 1183 } |
1166 | 1184 |
1167 // After the visitor writes, it may have caused the socket to become write | 1185 // After the visitor writes, it may have caused the socket to become write |
1168 // blocked or the congestion manager to prohibit sending, so check again. | 1186 // blocked or the congestion manager to prohibit sending, so check again. |
1169 pending_handshake = visitor_->HasPendingHandshake() ? | |
1170 IS_HANDSHAKE : NOT_HANDSHAKE; | |
1171 if (visitor_->HasPendingWrites() && !resume_writes_alarm_->IsSet() && | 1187 if (visitor_->HasPendingWrites() && !resume_writes_alarm_->IsSet() && |
1172 CanWrite(NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, | 1188 CanWrite(NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA)) { |
1173 pending_handshake)) { | |
1174 // We're not write blocked, but some stream didn't write out all of its | 1189 // We're not write blocked, but some stream didn't write out all of its |
1175 // bytes. Register for 'immediate' resumption so we'll keep writing after | 1190 // bytes. Register for 'immediate' resumption so we'll keep writing after |
1176 // other connections and events have had a chance to use the thread. | 1191 // other connections and events have had a chance to use the thread. |
1177 resume_writes_alarm_->Set(clock_->ApproximateNow()); | 1192 resume_writes_alarm_->Set(clock_->ApproximateNow()); |
1178 } | 1193 } |
1179 } | 1194 } |
1180 | 1195 |
1181 void QuicConnection::WriteIfNotBlocked() { | 1196 void QuicConnection::WriteIfNotBlocked() { |
1182 if (!writer_->IsWriteBlocked()) { | 1197 if (!writer_->IsWriteBlocked()) { |
1183 OnCanWrite(); | 1198 OnCanWrite(); |
1184 } | 1199 } |
1185 } | 1200 } |
1186 | 1201 |
1187 bool QuicConnection::ProcessValidatedPacket() { | 1202 bool QuicConnection::ProcessValidatedPacket() { |
1188 if (address_migrating_) { | 1203 if ((!FLAGS_quic_allow_port_migration && peer_port_changed_) || |
| 1204 peer_ip_changed_ || self_ip_changed_ || self_port_changed_) { |
1189 SendConnectionCloseWithDetails( | 1205 SendConnectionCloseWithDetails( |
1190 QUIC_ERROR_MIGRATING_ADDRESS, | 1206 QUIC_ERROR_MIGRATING_ADDRESS, |
1191 "Address migration is not yet a supported feature"); | 1207 "IP or port migration is not yet a supported feature"); |
1192 return false; | 1208 return false; |
1193 } | 1209 } |
| 1210 |
| 1211 // Port migration is supported, do it now if port has changed. |
| 1212 if (FLAGS_quic_allow_port_migration && |
| 1213 peer_port_changed_) { |
| 1214 DVLOG(1) << ENDPOINT << "Peer's port changed from " |
| 1215 << peer_address_.port() << " to " << migrating_peer_port_ |
| 1216 << ", migrating connection."; |
| 1217 peer_address_ = IPEndPoint(peer_address_.address(), migrating_peer_port_); |
| 1218 } |
| 1219 |
1194 time_of_last_received_packet_ = clock_->Now(); | 1220 time_of_last_received_packet_ = clock_->Now(); |
1195 DVLOG(1) << ENDPOINT << "time of last received packet: " | 1221 DVLOG(1) << ENDPOINT << "time of last received packet: " |
1196 << time_of_last_received_packet_.ToDebuggingValue(); | 1222 << time_of_last_received_packet_.ToDebuggingValue(); |
1197 | 1223 |
1198 if (is_server_ && encryption_level_ == ENCRYPTION_NONE && | 1224 if (is_server_ && encryption_level_ == ENCRYPTION_NONE && |
1199 last_size_ > options()->max_packet_length) { | 1225 last_size_ > options()->max_packet_length) { |
1200 options()->max_packet_length = last_size_; | 1226 options()->max_packet_length = last_size_; |
1201 } | 1227 } |
1202 return true; | 1228 return true; |
1203 } | 1229 } |
(...skipping 19 matching lines...) Expand all Loading... |
1223 } | 1249 } |
1224 } | 1250 } |
1225 | 1251 |
1226 void QuicConnection::WritePendingRetransmissions() { | 1252 void QuicConnection::WritePendingRetransmissions() { |
1227 // Keep writing as long as there's a pending retransmission which can be | 1253 // Keep writing as long as there's a pending retransmission which can be |
1228 // written. | 1254 // written. |
1229 while (sent_packet_manager_.HasPendingRetransmissions()) { | 1255 while (sent_packet_manager_.HasPendingRetransmissions()) { |
1230 const QuicSentPacketManager::PendingRetransmission pending = | 1256 const QuicSentPacketManager::PendingRetransmission pending = |
1231 sent_packet_manager_.NextPendingRetransmission(); | 1257 sent_packet_manager_.NextPendingRetransmission(); |
1232 if (GetPacketType(&pending.retransmittable_frames) == NORMAL && | 1258 if (GetPacketType(&pending.retransmittable_frames) == NORMAL && |
1233 !CanWrite(pending.transmission_type, HAS_RETRANSMITTABLE_DATA, | 1259 !CanWrite(pending.transmission_type, HAS_RETRANSMITTABLE_DATA)) { |
1234 pending.retransmittable_frames.HasCryptoHandshake())) { | |
1235 break; | 1260 break; |
1236 } | 1261 } |
1237 | 1262 |
1238 // Re-packetize the frames with a new sequence number for retransmission. | 1263 // Re-packetize the frames with a new sequence number for retransmission. |
1239 // Retransmitted data packets do not use FEC, even when it's enabled. | 1264 // Retransmitted data packets do not use FEC, even when it's enabled. |
1240 // Retransmitted packets use the same sequence number length as the | 1265 // Retransmitted packets use the same sequence number length as the |
1241 // original. | 1266 // original. |
1242 // Flush the packet creator before making a new packet. | 1267 // Flush the packet creator before making a new packet. |
1243 // TODO(ianswett): Implement ReserializeAllFrames as a separate path that | 1268 // TODO(ianswett): Implement ReserializeAllFrames as a separate path that |
1244 // does not require the creator to be flushed. | 1269 // does not require the creator to be flushed. |
(...skipping 17 matching lines...) Expand all Loading... |
1262 } | 1287 } |
1263 } | 1288 } |
1264 | 1289 |
1265 void QuicConnection::RetransmitUnackedPackets( | 1290 void QuicConnection::RetransmitUnackedPackets( |
1266 RetransmissionType retransmission_type) { | 1291 RetransmissionType retransmission_type) { |
1267 sent_packet_manager_.RetransmitUnackedPackets(retransmission_type); | 1292 sent_packet_manager_.RetransmitUnackedPackets(retransmission_type); |
1268 | 1293 |
1269 WriteIfNotBlocked(); | 1294 WriteIfNotBlocked(); |
1270 } | 1295 } |
1271 | 1296 |
1272 void QuicConnection::DiscardUnencryptedPackets() { | 1297 void QuicConnection::NeuterUnencryptedPackets() { |
1273 sent_packet_manager_.DiscardUnencryptedPackets(); | 1298 sent_packet_manager_.NeuterUnencryptedPackets(); |
1274 // This may have changed the retransmission timer, so re-arm it. | 1299 // This may have changed the retransmission timer, so re-arm it. |
1275 retransmission_alarm_->Cancel(); | 1300 retransmission_alarm_->Cancel(); |
1276 QuicTime retransmission_time = sent_packet_manager_.GetRetransmissionTime(); | 1301 QuicTime retransmission_time = sent_packet_manager_.GetRetransmissionTime(); |
1277 if (retransmission_time != QuicTime::Zero()) { | 1302 if (retransmission_time != QuicTime::Zero()) { |
1278 retransmission_alarm_->Set(retransmission_time); | 1303 retransmission_alarm_->Set(retransmission_time); |
1279 } | 1304 } |
1280 } | 1305 } |
1281 | 1306 |
1282 bool QuicConnection::ShouldGeneratePacket( | 1307 bool QuicConnection::ShouldGeneratePacket( |
1283 TransmissionType transmission_type, | 1308 TransmissionType transmission_type, |
1284 HasRetransmittableData retransmittable, | 1309 HasRetransmittableData retransmittable, |
1285 IsHandshake handshake) { | 1310 IsHandshake handshake) { |
1286 // We should serialize handshake packets immediately to ensure that they | 1311 // We should serialize handshake packets immediately to ensure that they |
1287 // end up sent at the right encryption level. | 1312 // end up sent at the right encryption level. |
1288 if (handshake == IS_HANDSHAKE) { | 1313 if (handshake == IS_HANDSHAKE) { |
1289 return true; | 1314 return true; |
1290 } | 1315 } |
1291 | 1316 |
1292 return CanWrite(transmission_type, retransmittable, handshake); | 1317 return CanWrite(transmission_type, retransmittable); |
1293 } | 1318 } |
1294 | 1319 |
1295 bool QuicConnection::CanWrite(TransmissionType transmission_type, | 1320 bool QuicConnection::CanWrite(TransmissionType transmission_type, |
1296 HasRetransmittableData retransmittable, | 1321 HasRetransmittableData retransmittable) { |
1297 IsHandshake handshake) { | |
1298 if (writer_->IsWriteBlocked()) { | 1322 if (writer_->IsWriteBlocked()) { |
1299 visitor_->OnWriteBlocked(); | 1323 visitor_->OnWriteBlocked(); |
1300 return false; | 1324 return false; |
1301 } | 1325 } |
1302 | 1326 |
1303 // TODO(rch): consider removing this check so that if an ACK comes in | 1327 // TODO(rch): consider removing this check so that if an ACK comes in |
1304 // before the alarm goes it, we might be able send out a packet. | 1328 // before the alarm goes it, we might be able send out a packet. |
1305 // This check assumes that if the send alarm is set, it applies equally to all | 1329 // This check assumes that if the send alarm is set, it applies equally to all |
1306 // types of transmissions. | 1330 // types of transmissions. |
1307 if (send_alarm_->IsSet()) { | 1331 if (send_alarm_->IsSet()) { |
(...skipping 27 matching lines...) Expand all Loading... |
1335 return true; | 1359 return true; |
1336 } | 1360 } |
1337 | 1361 |
1338 // If the packet is CONNECTION_CLOSE, we need to try to send it immediately | 1362 // If the packet is CONNECTION_CLOSE, we need to try to send it immediately |
1339 // and encrypt it to hand it off to TimeWaitListManager. | 1363 // and encrypt it to hand it off to TimeWaitListManager. |
1340 // If the packet is QUEUED, we don't re-consult the congestion control. | 1364 // If the packet is QUEUED, we don't re-consult the congestion control. |
1341 // This ensures packets are sent in sequence number order. | 1365 // This ensures packets are sent in sequence number order. |
1342 // TODO(ianswett): The congestion control should have been consulted before | 1366 // TODO(ianswett): The congestion control should have been consulted before |
1343 // serializing the packet, so this could be turned into a LOG_IF(DFATAL). | 1367 // serializing the packet, so this could be turned into a LOG_IF(DFATAL). |
1344 if (packet.type == NORMAL && !CanWrite(packet.transmission_type, | 1368 if (packet.type == NORMAL && !CanWrite(packet.transmission_type, |
1345 packet.retransmittable, | 1369 packet.retransmittable)) { |
1346 packet.handshake)) { | |
1347 return false; | 1370 return false; |
1348 } | 1371 } |
1349 | 1372 |
1350 // Some encryption algorithms require the packet sequence numbers not be | 1373 // Some encryption algorithms require the packet sequence numbers not be |
1351 // repeated. | 1374 // repeated. |
1352 DCHECK_LE(sequence_number_of_last_sent_packet_, sequence_number); | 1375 DCHECK_LE(sequence_number_of_last_sent_packet_, sequence_number); |
1353 sequence_number_of_last_sent_packet_ = sequence_number; | 1376 sequence_number_of_last_sent_packet_ = sequence_number; |
1354 | 1377 |
1355 QuicEncryptedPacket* encrypted = framer_.EncryptPacket( | 1378 QuicEncryptedPacket* encrypted = framer_.EncryptPacket( |
1356 packet.encryption_level, sequence_number, *packet.packet); | 1379 packet.encryption_level, sequence_number, *packet.packet); |
(...skipping 609 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1966 // If we changed the generator's batch state, restore original batch state. | 1989 // If we changed the generator's batch state, restore original batch state. |
1967 if (!already_in_batch_mode_) { | 1990 if (!already_in_batch_mode_) { |
1968 DVLOG(1) << "Leaving Batch Mode."; | 1991 DVLOG(1) << "Leaving Batch Mode."; |
1969 connection_->packet_generator_.FinishBatchOperations(); | 1992 connection_->packet_generator_.FinishBatchOperations(); |
1970 } | 1993 } |
1971 DCHECK_EQ(already_in_batch_mode_, | 1994 DCHECK_EQ(already_in_batch_mode_, |
1972 connection_->packet_generator_.InBatchMode()); | 1995 connection_->packet_generator_.InBatchMode()); |
1973 } | 1996 } |
1974 | 1997 |
1975 } // namespace net | 1998 } // namespace net |
OLD | NEW |