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/tools/quic/quic_dispatcher.h" | 5 #include "net/tools/quic/quic_dispatcher.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/macros.h" | 9 #include "base/macros.h" |
10 #include "net/quic/core/crypto/quic_random.h" | 10 #include "net/quic/core/crypto/quic_random.h" |
(...skipping 318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
329 framer_.set_version(version); | 329 framer_.set_version(version); |
330 return true; | 330 return true; |
331 } | 331 } |
332 | 332 |
333 bool QuicDispatcher::OnUnauthenticatedHeader(const QuicPacketHeader& header) { | 333 bool QuicDispatcher::OnUnauthenticatedHeader(const QuicPacketHeader& header) { |
334 QuicConnectionId connection_id = header.public_header.connection_id; | 334 QuicConnectionId connection_id = header.public_header.connection_id; |
335 | 335 |
336 if (time_wait_list_manager_->IsConnectionIdInTimeWait( | 336 if (time_wait_list_manager_->IsConnectionIdInTimeWait( |
337 header.public_header.connection_id)) { | 337 header.public_header.connection_id)) { |
338 // This connection ID is already in time-wait state. | 338 // This connection ID is already in time-wait state. |
339 time_wait_list_manager_->ProcessPacket( | 339 time_wait_list_manager_->ProcessPacket(current_server_address_, |
340 current_server_address_, current_client_address_, | 340 current_client_address_, |
341 header.public_header.connection_id, header.packet_number, | 341 header.public_header.connection_id); |
342 *current_packet_); | |
343 return false; | 342 return false; |
344 } | 343 } |
345 | 344 |
346 // Packet's connection ID is unknown. Apply the validity checks. | 345 // Packet's connection ID is unknown. Apply the validity checks. |
347 QuicPacketFate fate = ValidityChecks(header); | 346 QuicPacketFate fate = ValidityChecks(header); |
348 if (fate == kFateProcess) { | 347 if (fate == kFateProcess) { |
349 // Execute stateless rejection logic to determine the packet fate, then | 348 // Execute stateless rejection logic to determine the packet fate, then |
350 // invoke ProcessUnauthenticatedHeaderFate. | 349 // invoke ProcessUnauthenticatedHeaderFate. |
351 MaybeRejectStatelessly(connection_id, header); | 350 MaybeRejectStatelessly(connection_id, |
| 351 header.public_header.versions.front()); |
352 } else { | 352 } else { |
353 // If the fate is already known, process it without executing stateless | 353 // If the fate is already known, process it without executing stateless |
354 // rejection logic. | 354 // rejection logic. |
355 ProcessUnauthenticatedHeaderFate(fate, connection_id, header.packet_number); | 355 ProcessUnauthenticatedHeaderFate(fate, connection_id); |
356 } | 356 } |
357 | 357 |
358 return false; | 358 return false; |
359 } | 359 } |
360 | 360 |
361 void QuicDispatcher::ProcessUnauthenticatedHeaderFate( | 361 void QuicDispatcher::ProcessUnauthenticatedHeaderFate( |
362 QuicPacketFate fate, | 362 QuicPacketFate fate, |
363 QuicConnectionId connection_id, | 363 QuicConnectionId connection_id) { |
364 QuicPacketNumber packet_number) { | |
365 switch (fate) { | 364 switch (fate) { |
366 case kFateProcess: { | 365 case kFateProcess: { |
367 ProcessChlo(packet_number); | 366 ProcessChlo(); |
368 break; | 367 break; |
369 } | 368 } |
370 case kFateTimeWait: | 369 case kFateTimeWait: |
371 // MaybeRejectStatelessly or OnExpiredPackets might have already added the | 370 // MaybeRejectStatelessly or OnExpiredPackets might have already added the |
372 // connection to time wait, in which case it should not be added again. | 371 // connection to time wait, in which case it should not be added again. |
373 if (!FLAGS_quic_reloadable_flag_quic_use_cheap_stateless_rejects || | 372 if (!FLAGS_quic_reloadable_flag_quic_use_cheap_stateless_rejects || |
374 !time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)) { | 373 !time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)) { |
375 // Add this connection_id to the time-wait state, to safely reject | 374 // Add this connection_id to the time-wait state, to safely reject |
376 // future packets. | 375 // future packets. |
377 QUIC_DLOG(INFO) << "Adding connection ID " << connection_id | 376 QUIC_DLOG(INFO) << "Adding connection ID " << connection_id |
378 << "to time-wait list."; | 377 << "to time-wait list."; |
379 time_wait_list_manager_->AddConnectionIdToTimeWait( | 378 time_wait_list_manager_->AddConnectionIdToTimeWait( |
380 connection_id, framer_.version(), | 379 connection_id, framer_.version(), |
381 /*connection_rejected_statelessly=*/false, nullptr); | 380 /*connection_rejected_statelessly=*/false, nullptr); |
382 } | 381 } |
383 DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)); | 382 DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)); |
384 time_wait_list_manager_->ProcessPacket( | 383 time_wait_list_manager_->ProcessPacket( |
385 current_server_address_, current_client_address_, connection_id, | 384 current_server_address_, current_client_address_, connection_id); |
386 packet_number, *current_packet_); | |
387 | 385 |
388 // Any packets which were buffered while the stateless rejector logic was | 386 // Any packets which were buffered while the stateless rejector logic was |
389 // running should be discarded. Do not inform the time wait list manager, | 387 // running should be discarded. Do not inform the time wait list manager, |
390 // which should already have a made a decision about sending a reject | 388 // which should already have a made a decision about sending a reject |
391 // based on the CHLO alone. | 389 // based on the CHLO alone. |
392 buffered_packets_.DiscardPackets(connection_id); | 390 buffered_packets_.DiscardPackets(connection_id); |
393 break; | 391 break; |
394 case kFateBuffer: | 392 case kFateBuffer: |
395 // This packet is a non-CHLO packet which has arrived before the | 393 // This packet is a non-CHLO packet which has arrived before the |
396 // corresponding CHLO, *or* this packet was received while the | 394 // corresponding CHLO, *or* this packet was received while the |
(...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
710 connection_id, *current_packet_, current_server_address_, | 708 connection_id, *current_packet_, current_server_address_, |
711 current_client_address_, /*is_chlo=*/false); | 709 current_client_address_, /*is_chlo=*/false); |
712 if (rs != EnqueuePacketResult::SUCCESS) { | 710 if (rs != EnqueuePacketResult::SUCCESS) { |
713 OnBufferPacketFailure(rs, connection_id); | 711 OnBufferPacketFailure(rs, connection_id); |
714 } else if (!FLAGS_quic_reloadable_flag_quic_create_session_after_insertion && | 712 } else if (!FLAGS_quic_reloadable_flag_quic_create_session_after_insertion && |
715 is_new_connection) { | 713 is_new_connection) { |
716 ShouldCreateOrBufferPacketForConnection(connection_id); | 714 ShouldCreateOrBufferPacketForConnection(connection_id); |
717 } | 715 } |
718 } | 716 } |
719 | 717 |
720 void QuicDispatcher::ProcessChlo(QuicPacketNumber packet_number) { | 718 void QuicDispatcher::ProcessChlo() { |
721 if (!accept_new_connections_) { | 719 if (!accept_new_connections_) { |
722 // Don't any create new connection. | 720 // Don't any create new connection. |
723 time_wait_list_manager()->AddConnectionIdToTimeWait( | 721 time_wait_list_manager()->AddConnectionIdToTimeWait( |
724 current_connection_id(), framer()->version(), | 722 current_connection_id(), framer()->version(), |
725 /*connection_rejected_statelessly=*/false, | 723 /*connection_rejected_statelessly=*/false, |
726 /*termination_packets=*/nullptr); | 724 /*termination_packets=*/nullptr); |
727 // This will trigger sending Public Reset packet. | 725 // This will trigger sending Public Reset packet. |
728 time_wait_list_manager()->ProcessPacket( | 726 time_wait_list_manager()->ProcessPacket(current_server_address(), |
729 current_server_address(), current_client_address(), | 727 current_client_address(), |
730 current_connection_id(), packet_number, current_packet()); | 728 current_connection_id()); |
731 return; | 729 return; |
732 } | 730 } |
733 if (FLAGS_quic_reloadable_flag_quic_create_session_after_insertion && | 731 if (FLAGS_quic_reloadable_flag_quic_create_session_after_insertion && |
734 !buffered_packets_.HasBufferedPackets(current_connection_id_) && | 732 !buffered_packets_.HasBufferedPackets(current_connection_id_) && |
735 !ShouldCreateOrBufferPacketForConnection(current_connection_id_)) { | 733 !ShouldCreateOrBufferPacketForConnection(current_connection_id_)) { |
736 QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_create_session_after_insertion, | 734 QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_create_session_after_insertion, |
737 2, 5); | 735 2, 5); |
738 return; | 736 return; |
739 } | 737 } |
740 if (FLAGS_quic_allow_chlo_buffering && | 738 if (FLAGS_quic_allow_chlo_buffering && |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
808 | 806 |
809 bool QuicDispatcher::OnUnauthenticatedUnknownPublicHeader( | 807 bool QuicDispatcher::OnUnauthenticatedUnknownPublicHeader( |
810 const QuicPacketPublicHeader& header) { | 808 const QuicPacketPublicHeader& header) { |
811 return true; | 809 return true; |
812 } | 810 } |
813 | 811 |
814 class StatelessRejectorProcessDoneCallback | 812 class StatelessRejectorProcessDoneCallback |
815 : public StatelessRejector::ProcessDoneCallback { | 813 : public StatelessRejector::ProcessDoneCallback { |
816 public: | 814 public: |
817 StatelessRejectorProcessDoneCallback(QuicDispatcher* dispatcher, | 815 StatelessRejectorProcessDoneCallback(QuicDispatcher* dispatcher, |
818 QuicPacketNumber packet_number, | |
819 QuicVersion first_version) | 816 QuicVersion first_version) |
820 : dispatcher_(dispatcher), | 817 : dispatcher_(dispatcher), |
821 current_client_address_(dispatcher->current_client_address_), | 818 current_client_address_(dispatcher->current_client_address_), |
822 current_server_address_(dispatcher->current_server_address_), | 819 current_server_address_(dispatcher->current_server_address_), |
823 current_packet_( | 820 current_packet_( |
824 dispatcher->current_packet_->Clone()), // Note: copies the packet | 821 dispatcher->current_packet_->Clone()), // Note: copies the packet |
825 packet_number_(packet_number), | |
826 first_version_(first_version) {} | 822 first_version_(first_version) {} |
827 | 823 |
828 void Run(std::unique_ptr<StatelessRejector> rejector) override { | 824 void Run(std::unique_ptr<StatelessRejector> rejector) override { |
829 dispatcher_->OnStatelessRejectorProcessDone( | 825 dispatcher_->OnStatelessRejectorProcessDone( |
830 std::move(rejector), current_client_address_, current_server_address_, | 826 std::move(rejector), current_client_address_, current_server_address_, |
831 std::move(current_packet_), packet_number_, first_version_); | 827 std::move(current_packet_), first_version_); |
832 } | 828 } |
833 | 829 |
834 private: | 830 private: |
835 QuicDispatcher* dispatcher_; | 831 QuicDispatcher* dispatcher_; |
836 QuicSocketAddress current_client_address_; | 832 QuicSocketAddress current_client_address_; |
837 QuicSocketAddress current_server_address_; | 833 QuicSocketAddress current_server_address_; |
838 std::unique_ptr<QuicReceivedPacket> current_packet_; | 834 std::unique_ptr<QuicReceivedPacket> current_packet_; |
839 QuicPacketNumber packet_number_; | |
840 QuicVersion first_version_; | 835 QuicVersion first_version_; |
841 }; | 836 }; |
842 | 837 |
843 void QuicDispatcher::MaybeRejectStatelessly(QuicConnectionId connection_id, | 838 void QuicDispatcher::MaybeRejectStatelessly(QuicConnectionId connection_id, |
844 const QuicPacketHeader& header) { | 839 QuicVersion version) { |
845 // TODO(rch): This logic should probably live completely inside the rejector. | 840 // TODO(rch): This logic should probably live completely inside the rejector. |
846 if (!FLAGS_quic_allow_chlo_buffering || | 841 if (!FLAGS_quic_allow_chlo_buffering || |
847 !FLAGS_quic_reloadable_flag_quic_use_cheap_stateless_rejects || | 842 !FLAGS_quic_reloadable_flag_quic_use_cheap_stateless_rejects || |
848 !FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support || | 843 !FLAGS_quic_reloadable_flag_enable_quic_stateless_reject_support || |
849 !ShouldAttemptCheapStatelessRejection()) { | 844 !ShouldAttemptCheapStatelessRejection()) { |
850 // Not use cheap stateless reject. | 845 // Not use cheap stateless reject. |
851 if (FLAGS_quic_allow_chlo_buffering && | 846 if (FLAGS_quic_allow_chlo_buffering && |
852 !ChloExtractor::Extract(*current_packet_, GetSupportedVersions(), | 847 !ChloExtractor::Extract(*current_packet_, GetSupportedVersions(), |
853 nullptr)) { | 848 nullptr)) { |
854 // Buffer non-CHLO packets. | 849 // Buffer non-CHLO packets. |
855 ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id, | 850 ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id); |
856 header.packet_number); | |
857 return; | 851 return; |
858 } | 852 } |
859 ProcessUnauthenticatedHeaderFate(kFateProcess, connection_id, | 853 ProcessUnauthenticatedHeaderFate(kFateProcess, connection_id); |
860 header.packet_number); | |
861 return; | 854 return; |
862 } | 855 } |
863 | 856 |
864 std::unique_ptr<StatelessRejector> rejector(new StatelessRejector( | 857 std::unique_ptr<StatelessRejector> rejector(new StatelessRejector( |
865 header.public_header.versions.front(), GetSupportedVersions(), | 858 version, GetSupportedVersions(), crypto_config_, &compressed_certs_cache_, |
866 crypto_config_, &compressed_certs_cache_, helper()->GetClock(), | 859 helper()->GetClock(), helper()->GetRandomGenerator(), |
867 helper()->GetRandomGenerator(), current_packet_->length(), | 860 current_packet_->length(), current_client_address_, |
868 current_client_address_, current_server_address_)); | 861 current_server_address_)); |
869 ChloValidator validator(session_helper_.get(), current_server_address_, | 862 ChloValidator validator(session_helper_.get(), current_server_address_, |
870 rejector.get()); | 863 rejector.get()); |
871 if (!ChloExtractor::Extract(*current_packet_, GetSupportedVersions(), | 864 if (!ChloExtractor::Extract(*current_packet_, GetSupportedVersions(), |
872 &validator)) { | 865 &validator)) { |
873 ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id, | 866 ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id); |
874 header.packet_number); | |
875 return; | 867 return; |
876 } | 868 } |
877 | 869 |
878 if (!validator.can_accept()) { | 870 if (!validator.can_accept()) { |
879 // This CHLO is prohibited by policy. | 871 // This CHLO is prohibited by policy. |
880 StatelessConnectionTerminator terminator(connection_id, &framer_, helper(), | 872 StatelessConnectionTerminator terminator(connection_id, &framer_, helper(), |
881 time_wait_list_manager_.get()); | 873 time_wait_list_manager_.get()); |
882 terminator.CloseConnection(QUIC_HANDSHAKE_FAILED, | 874 terminator.CloseConnection(QUIC_HANDSHAKE_FAILED, |
883 validator.error_details()); | 875 validator.error_details()); |
884 OnConnectionClosedStatelessly(QUIC_HANDSHAKE_FAILED); | 876 OnConnectionClosedStatelessly(QUIC_HANDSHAKE_FAILED); |
885 ProcessUnauthenticatedHeaderFate(kFateTimeWait, connection_id, | 877 ProcessUnauthenticatedHeaderFate(kFateTimeWait, connection_id); |
886 header.packet_number); | |
887 return; | 878 return; |
888 } | 879 } |
889 | 880 |
890 // If we were able to make a decision about this CHLO based purely on the | 881 // If we were able to make a decision about this CHLO based purely on the |
891 // information available in OnChlo, just invoke the done callback immediately. | 882 // information available in OnChlo, just invoke the done callback immediately. |
892 if (rejector->state() != StatelessRejector::UNKNOWN) { | 883 if (rejector->state() != StatelessRejector::UNKNOWN) { |
893 ProcessStatelessRejectorState(std::move(rejector), header.packet_number, | 884 ProcessStatelessRejectorState(std::move(rejector), version); |
894 header.public_header.versions.front()); | |
895 return; | 885 return; |
896 } | 886 } |
897 | 887 |
898 // Insert into set of connection IDs to buffer | 888 // Insert into set of connection IDs to buffer |
899 const bool ok = | 889 const bool ok = |
900 temporarily_buffered_connections_.insert(connection_id).second; | 890 temporarily_buffered_connections_.insert(connection_id).second; |
901 QUIC_BUG_IF(!ok) | 891 QUIC_BUG_IF(!ok) |
902 << "Processing multiple stateless rejections for connection ID " | 892 << "Processing multiple stateless rejections for connection ID " |
903 << connection_id; | 893 << connection_id; |
904 | 894 |
905 // Continue stateless rejector processing | 895 // Continue stateless rejector processing |
906 std::unique_ptr<StatelessRejectorProcessDoneCallback> cb( | 896 std::unique_ptr<StatelessRejectorProcessDoneCallback> cb( |
907 new StatelessRejectorProcessDoneCallback( | 897 new StatelessRejectorProcessDoneCallback(this, version)); |
908 this, header.packet_number, header.public_header.versions.front())); | |
909 StatelessRejector::Process(std::move(rejector), std::move(cb)); | 898 StatelessRejector::Process(std::move(rejector), std::move(cb)); |
910 } | 899 } |
911 | 900 |
912 void QuicDispatcher::OnStatelessRejectorProcessDone( | 901 void QuicDispatcher::OnStatelessRejectorProcessDone( |
913 std::unique_ptr<StatelessRejector> rejector, | 902 std::unique_ptr<StatelessRejector> rejector, |
914 const QuicSocketAddress& current_client_address, | 903 const QuicSocketAddress& current_client_address, |
915 const QuicSocketAddress& current_server_address, | 904 const QuicSocketAddress& current_server_address, |
916 std::unique_ptr<QuicReceivedPacket> current_packet, | 905 std::unique_ptr<QuicReceivedPacket> current_packet, |
917 QuicPacketNumber packet_number, | |
918 QuicVersion first_version) { | 906 QuicVersion first_version) { |
919 // Stop buffering packets on this connection | 907 // Stop buffering packets on this connection |
920 const auto num_erased = | 908 const auto num_erased = |
921 temporarily_buffered_connections_.erase(rejector->connection_id()); | 909 temporarily_buffered_connections_.erase(rejector->connection_id()); |
922 QUIC_BUG_IF(num_erased != 1) << "Completing stateless rejection logic for " | 910 QUIC_BUG_IF(num_erased != 1) << "Completing stateless rejection logic for " |
923 "non-buffered connection ID " | 911 "non-buffered connection ID " |
924 << rejector->connection_id(); | 912 << rejector->connection_id(); |
925 | 913 |
926 // If this connection has gone into time-wait during the async processing, | 914 // If this connection has gone into time-wait during the async processing, |
927 // don't proceed. | 915 // don't proceed. |
928 if (time_wait_list_manager_->IsConnectionIdInTimeWait( | 916 if (time_wait_list_manager_->IsConnectionIdInTimeWait( |
929 rejector->connection_id())) { | 917 rejector->connection_id())) { |
930 time_wait_list_manager_->ProcessPacket( | 918 time_wait_list_manager_->ProcessPacket(current_server_address, |
931 current_server_address, current_client_address, | 919 current_client_address, |
932 rejector->connection_id(), packet_number, *current_packet); | 920 rejector->connection_id()); |
933 return; | 921 return; |
934 } | 922 } |
935 | 923 |
936 // Reset current_* to correspond to the packet which initiated the stateless | 924 // Reset current_* to correspond to the packet which initiated the stateless |
937 // reject logic. | 925 // reject logic. |
938 current_client_address_ = current_client_address; | 926 current_client_address_ = current_client_address; |
939 current_server_address_ = current_server_address; | 927 current_server_address_ = current_server_address; |
940 current_packet_ = current_packet.get(); | 928 current_packet_ = current_packet.get(); |
941 current_connection_id_ = rejector->connection_id(); | 929 current_connection_id_ = rejector->connection_id(); |
942 | 930 |
943 ProcessStatelessRejectorState(std::move(rejector), packet_number, | 931 ProcessStatelessRejectorState(std::move(rejector), first_version); |
944 first_version); | |
945 } | 932 } |
946 | 933 |
947 void QuicDispatcher::ProcessStatelessRejectorState( | 934 void QuicDispatcher::ProcessStatelessRejectorState( |
948 std::unique_ptr<StatelessRejector> rejector, | 935 std::unique_ptr<StatelessRejector> rejector, |
949 QuicPacketNumber packet_number, | |
950 QuicVersion first_version) { | 936 QuicVersion first_version) { |
951 QuicPacketFate fate; | 937 QuicPacketFate fate; |
952 switch (rejector->state()) { | 938 switch (rejector->state()) { |
953 case StatelessRejector::FAILED: { | 939 case StatelessRejector::FAILED: { |
954 // There was an error processing the client hello. | 940 // There was an error processing the client hello. |
955 StatelessConnectionTerminator terminator(rejector->connection_id(), | 941 StatelessConnectionTerminator terminator(rejector->connection_id(), |
956 &framer_, helper(), | 942 &framer_, helper(), |
957 time_wait_list_manager_.get()); | 943 time_wait_list_manager_.get()); |
958 terminator.CloseConnection(rejector->error(), rejector->error_details()); | 944 terminator.CloseConnection(rejector->error(), rejector->error_details()); |
959 fate = kFateTimeWait; | 945 fate = kFateTimeWait; |
(...skipping 21 matching lines...) Expand all Loading... |
981 OnConnectionRejectedStatelessly(); | 967 OnConnectionRejectedStatelessly(); |
982 fate = kFateTimeWait; | 968 fate = kFateTimeWait; |
983 break; | 969 break; |
984 } | 970 } |
985 | 971 |
986 default: | 972 default: |
987 QUIC_BUG << "Rejector has invalid state " << rejector->state(); | 973 QUIC_BUG << "Rejector has invalid state " << rejector->state(); |
988 fate = kFateDrop; | 974 fate = kFateDrop; |
989 break; | 975 break; |
990 } | 976 } |
991 ProcessUnauthenticatedHeaderFate(fate, rejector->connection_id(), | 977 ProcessUnauthenticatedHeaderFate(fate, rejector->connection_id()); |
992 packet_number); | |
993 } | 978 } |
994 | 979 |
995 const QuicVersionVector& QuicDispatcher::GetSupportedVersions() { | 980 const QuicVersionVector& QuicDispatcher::GetSupportedVersions() { |
996 return version_manager_->GetSupportedVersions(); | 981 return version_manager_->GetSupportedVersions(); |
997 } | 982 } |
998 | 983 |
999 void QuicDispatcher::DeliverPacketsToSession( | 984 void QuicDispatcher::DeliverPacketsToSession( |
1000 const std::list<BufferedPacket>& packets, | 985 const std::list<BufferedPacket>& packets, |
1001 QuicSession* session) { | 986 QuicSession* session) { |
1002 for (const BufferedPacket& packet : packets) { | 987 for (const BufferedPacket& packet : packets) { |
1003 session->ProcessUdpPacket(packet.server_address, packet.client_address, | 988 session->ProcessUdpPacket(packet.server_address, packet.client_address, |
1004 *(packet.packet)); | 989 *(packet.packet)); |
1005 } | 990 } |
1006 } | 991 } |
1007 | 992 |
1008 } // namespace net | 993 } // namespace net |
OLD | NEW |