├── LICENSE ├── README.md ├── plot-script └── data-plot.sh ├── quic ├── model │ ├── cc-algo │ │ ├── cdg_sender.cc │ │ ├── cdg_sender.h │ │ ├── cong_state.h │ │ ├── copa_sender.cc │ │ ├── copa_sender.h │ │ ├── vegas_sender.cc │ │ └── vegas_sender.h │ ├── ns3-client-network-helper.cc │ ├── ns3-client-network-helper.h │ ├── ns3-packet-writer.cc │ ├── ns3-packet-writer.h │ ├── ns3-quic-addr-convert.h │ ├── ns3-quic-addr-pair.h │ ├── ns3-quic-alarm-engine.cc │ ├── ns3-quic-alarm-engine.h │ ├── ns3-quic-backend.cc │ ├── ns3-quic-backend.h │ ├── ns3-quic-channel.cc │ ├── ns3-quic-channel.h │ ├── ns3-quic-client-app.cc │ ├── ns3-quic-client-app.h │ ├── ns3-quic-client-session.cc │ ├── ns3-quic-client-session.h │ ├── ns3-quic-client.cc │ ├── ns3-quic-client.h │ ├── ns3-quic-clock.cc │ ├── ns3-quic-clock.h │ ├── ns3-quic-congestion-factory.cc │ ├── ns3-quic-congestion-factory.h │ ├── ns3-quic-connection-helper.cc │ ├── ns3-quic-connection-helper.h │ ├── ns3-quic-dispatcher.cc │ ├── ns3-quic-dispatcher.h │ ├── ns3-quic-flags.cc │ ├── ns3-quic-flags.h │ ├── ns3-quic-no-destructor.h │ ├── ns3-quic-poll-server.h │ ├── ns3-quic-private.h │ ├── ns3-quic-public.h │ ├── ns3-quic-server-app.cc │ ├── ns3-quic-server-app.h │ ├── ns3-quic-server-session.cc │ ├── ns3-quic-server-session.h │ ├── ns3-quic-server.cc │ ├── ns3-quic-server.h │ ├── ns3-quic-session-base.cc │ ├── ns3-quic-session-base.h │ ├── ns3-quic-tag.cc │ ├── ns3-quic-tag.h │ ├── ns3-quic-trace.cc │ ├── ns3-quic-trace.h │ ├── ns3-quic-util.cc │ ├── ns3-quic-util.h │ ├── ns3-transport-stream.cc │ ├── ns3-transport-stream.h │ ├── quic-test.cc │ └── quic-test.h └── wscript ├── results ├── 1-bbr-inflight.png ├── 1-bbr-owd.png ├── 1-bbr-send-rate.png ├── 1-copa-goodput.png ├── 1-copa-inflight.png ├── 1-copa-owd.png ├── 1-copa-send-rate.png ├── 1-cubic-inflight.png ├── 1-cubic-owd.png ├── 1-cubic-send-rate.png ├── 1-vegas-goodput.png ├── 1-vegas-inflight.png ├── 1-vegas-owd.png └── 1-vegas-send-rate.png └── scratch └── quic-main.cc /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # quic-on-ns3 2 | running google quic on ns3 3 | This repo depends on quiche library. 4 | The quiche library can be got here: https://github.com/bilibili/quiche 5 | I make some minor changes on CmakeList.txt to get shared library. 6 | Download quiche library on release page: https://github.com/SoonyangZhang/quic-on-ns3/releases/tag/quiche 7 | 8 | # Build quiche 9 | ## Prerequisite 10 | ``` 11 | apt-get install cmake build-essential protobuf-compiler libprotobuf-dev golang-go libunwind-dev libicu-dev 12 | ``` 13 | ## Build 14 | Download quiche library first. And I unzip the quiche.zip under "/home/xxx/" 15 | ``` 16 | cd quiche 17 | mkdir build && cd build 18 | cmake .. 19 | make 20 | ``` 21 | ## Generate cert 22 | ``` 23 | cd quiche/util 24 | chmod 777 generate-certs.sh 25 | ./generate-certs.sh 26 | mkdir -p data/quic-cert 27 | mv ./out/* data/quic-cert/ 28 | ``` 29 | # Build quic module on ns3 30 | The code of quic module is tested on ns3.33. 31 | ## Add environmental variable 32 | ``` 33 | sudo gedit /etc/profile 34 | export QUICHE_SRC_DIR=/home/xxx/quiche/ 35 | export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$QUICHE_SRC_DIR/build/ 36 | ``` 37 | The reason to add QUICHE_SRC_DIR can be found quic/wscript. 38 | ## build ns3 39 | cope quic folder to ns3.33/src/ 40 | ``` 41 | cd ns3.33 42 | CXXFLAGS="-std=c++17" 43 | source /etc/profile 44 | ./waf configure 45 | ./waf build 46 | ``` 47 | # Run example 48 | 1 put the file quic-main.cc(scratch) to ns3.33/scratch/ 49 | 2 Run example(BBR) 50 | ``` 51 | source /etc/profile 52 | ./waf --run "scratch/quic-main --cc=bbr" 53 | ``` 54 | 3 Run example(BBR) 55 | ``` 56 | source /etc/profile 57 | ./waf --run "scratch/quic-main --cc=cubic" 58 | ``` 59 | # Results 60 | data can be found under folder ("/home/xxx/traces/") 61 | copy the file plot-script/data_plot.sh to "/home/xxx/traces/bbr" 62 | plot the results: 63 | ``` 64 | chmod 777 data-plot.sh 65 | ./data-plot.sh bbr 1 66 | ``` 67 | ## bbr 68 | inflight packets: 69 | ![avatar](https://github.com/SoonyangZhang/quic-on-ns3/blob/main/results/1-bbr-inflight.png) 70 | one way delay: 71 | ![avatar](https://github.com/SoonyangZhang/quic-on-ns3/blob/main/results/1-bbr-owd.png) 72 | send rate: 73 | ![avatar](https://github.com/SoonyangZhang/quic-on-ns3/blob/main/results/1-bbr-send-rate.png) 74 | ## cubic 75 | inflight packets: 76 | ![avatar](https://github.com/SoonyangZhang/quic-on-ns3/blob/main/results/1-cubic-inflight.png) 77 | one way delay: 78 | ![avatar](https://github.com/SoonyangZhang/quic-on-ns3/blob/main/results/1-cubic-owd.png) 79 | send rate: 80 | ![avatar](https://github.com/SoonyangZhang/quic-on-ns3/blob/main/results/1-cubic-send-rate.png) 81 | ## copa 82 | one way delay: 83 | ![avatar](https://github.com/SoonyangZhang/quic-on-ns3/blob/main/results/1-copa-owd.png) 84 | goodput: 85 | ![avatar](https://github.com/SoonyangZhang/quic-on-ns3/blob/main/results/1-copa-goodput.png) 86 | ## vegas 87 | one way delay: 88 | ![avatar](https://github.com/SoonyangZhang/quic-on-ns3/blob/main/results/1-vegas-owd.png) 89 | goodput: 90 | ![avatar](https://github.com/SoonyangZhang/quic-on-ns3/blob/main/results/1-vegas-goodput.png) 91 | -------------------------------------------------------------------------------- /plot-script/data-plot.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | algo=$1 3 | id=$2 4 | prefix1=${id}_10.1.1.1:49153_10.1.1.2:1234 5 | prefix2=${id}_10.1.1.1:49154_10.1.1.2:1234 6 | prefix3=${id}_10.1.1.1:49155_10.1.1.2:1234 7 | file1=${prefix1}_sendrate.txt 8 | file2=${prefix2}_sendrate.txt 9 | file3=${prefix3}_sendrate.txt 10 | output=${id}-${algo} 11 | gnuplot< 4 | #include 5 | 6 | #include "gquiche/quic/core/congestion_control/hybrid_slow_start.h" 7 | #include "gquiche/quic/core/congestion_control/prr_sender.h" 8 | #include "gquiche/quic/core/congestion_control/send_algorithm_interface.h" 9 | #include "gquiche/quic/core/quic_bandwidth.h" 10 | #include "gquiche/quic/core/quic_connection_stats.h" 11 | #include "gquiche/quic/core/quic_packets.h" 12 | #include "gquiche/quic/core/quic_time.h" 13 | #include "gquiche/quic/platform/api/quic_export.h" 14 | #include "cong_state.h" 15 | namespace quic { 16 | 17 | class RttStats; 18 | class QuicRandom; 19 | // Maximum window to allow when doing bandwidth resumption. 20 | const QuicPacketCount kMaxResumptionCongestionWindow = 200; 21 | const int kRttWin=8; 22 | 23 | class QUIC_EXPORT_PRIVATE TcpCdgSenderBytes : public SendAlgorithmInterface { 24 | public: 25 | TcpCdgSenderBytes(const QuicClock* clock, const RttStats* rtt_stats, 26 | QuicPacketCount initial_tcp_congestion_window, 27 | QuicPacketCount max_congestion_window, 28 | QuicRandom* random, 29 | QuicConnectionStats* stats); 30 | TcpCdgSenderBytes(const TcpCdgSenderBytes&) = delete; 31 | TcpCdgSenderBytes& operator=(const TcpCdgSenderBytes&) = delete; 32 | ~TcpCdgSenderBytes() override; 33 | struct QUIC_EXPORT_PRIVATE DebugState { 34 | explicit DebugState(const TcpCdgSenderBytes& sender); 35 | DebugState(const DebugState& state); 36 | QuicTime::Delta min_rtt; 37 | QuicTime::Delta latest_rtt; 38 | QuicTime::Delta smoothed_rtt; 39 | QuicTime::Delta mean_deviation; 40 | QuicBandwidth bandwidth_est; 41 | }; 42 | 43 | // Start implementation of SendAlgorithmInterface. 44 | void SetFromConfig(const QuicConfig& config, 45 | Perspective perspective) override; 46 | void ApplyConnectionOptions( 47 | const QuicTagVector& /*connection_options*/) override {} 48 | void AdjustNetworkParameters(const NetworkParams& params) override; 49 | void SetNumEmulatedConnections(int num_connections); 50 | void SetInitialCongestionWindowInPackets( 51 | QuicPacketCount congestion_window) override; 52 | void SetExtraLossThreshold(float extra_loss_threshold) override; 53 | void SetUpdateRangeTime(QuicTime::Delta update_range_time) override; 54 | void SetIsUpdatePacketLostFlag(bool is_update_min_packet_lost) override; 55 | void SetUseBandwidthListFlag(bool is_use_bandwidth_list) override; 56 | void OnConnectionMigration() override; 57 | void OnCongestionEvent(bool rtt_updated, QuicByteCount prior_in_flight, 58 | QuicTime event_time, 59 | const AckedPacketVector& acked_packets, 60 | const LostPacketVector& lost_packets) override; 61 | void OnPacketSent(QuicTime sent_time, QuicByteCount bytes_in_flight, 62 | QuicPacketNumber packet_number, QuicByteCount bytes, 63 | HasRetransmittableData is_retransmittable) override; 64 | void OnPacketNeutered(QuicPacketNumber /*packet_number*/) override {} 65 | void OnRetransmissionTimeout(bool packets_retransmitted) override; 66 | bool CanSend(QuicByteCount bytes_in_flight) override; 67 | QuicBandwidth PacingRate(QuicByteCount bytes_in_flight) const override; 68 | QuicBandwidth BandwidthEstimate() const override; 69 | bool HasGoodBandwidthEstimateForResumption() const override { return false; } 70 | QuicByteCount GetCongestionWindow() const override; 71 | QuicByteCount GetSlowStartThreshold() const override; 72 | CongestionControlType GetCongestionControlType() const override; 73 | bool InSlowStart() const override; 74 | bool InRecovery() const override; 75 | std::string GetDebugState() const override; 76 | void OnApplicationLimited(QuicByteCount bytes_in_flight) override; 77 | void PopulateConnectionStats(QuicConnectionStats* /*stats*/) const override {} 78 | // End implementation of SendAlgorithmInterface. 79 | 80 | DebugState ExportDebugState() const; 81 | QuicByteCount min_congestion_window() const { return min_congestion_window_; } 82 | 83 | protected: 84 | // Compute the TCP Reno beta based on the current number of connections. 85 | float CdgBeta() const; 86 | 87 | bool IsCwndLimited(QuicByteCount bytes_in_flight) const; 88 | 89 | // TODO(ianswett): Remove these and migrate to OnCongestionEvent. 90 | void OnPacketAcked(QuicPacketNumber acked_packet_number, 91 | QuicByteCount acked_bytes, QuicByteCount prior_in_flight, 92 | QuicTime event_time); 93 | void SetCongestionWindowFromBandwidthAndRtt(QuicBandwidth bandwidth, 94 | QuicTime::Delta rtt); 95 | void SetMinCongestionWindowInPackets(QuicPacketCount congestion_window); 96 | void ExitSlowstart(); 97 | void OnPacketLost(QuicPacketNumber packet_number, QuicByteCount lost_bytes, 98 | QuicByteCount prior_in_flight); 99 | void MaybeIncreaseCwnd(QuicPacketNumber acked_packet_number, 100 | QuicByteCount acked_bytes, 101 | QuicByteCount prior_in_flight, QuicTime event_time); 102 | void HandleRetransmissionTimeout(); 103 | // Updates the round-trip counter if a round-trip has passed. Returns true if 104 | // the counter has been advanced. 105 | bool UpdateRoundTripCounter(QuicPacketNumber last_acked_packet); 106 | private: 107 | inline int32_t CalculateGrad(void); 108 | bool CdgBackoff(int32_t grad); 109 | void EnterCongestionWindowReduction(); 110 | QuicByteCount CdgGetSlowThreshold(); 111 | struct minmax { 112 | union { 113 | struct { 114 | int32_t min; 115 | int32_t max; 116 | }; 117 | uint64_t v64; 118 | }; 119 | }; 120 | 121 | enum cdg_state { 122 | CDG_UNKNOWN = 0, 123 | CDG_NONFULL = 1, 124 | CDG_FULL = 2, 125 | CDG_BACKOFF = 3, 126 | }; 127 | 128 | HybridSlowStart hybrid_slow_start_; 129 | PrrSender prr_; 130 | const RttStats* rtt_stats_; 131 | QuicRandom* random_; 132 | QuicConnectionStats* stats_; 133 | 134 | // Track the largest packet that has been sent. 135 | QuicPacketNumber largest_sent_packet_number_; 136 | // Acknowledgement of any packet after |current_round_trip_end_| will cause 137 | // the round trip counter to advance. 138 | QuicPacketNumber current_round_trip_end_; 139 | // Track the largest packet that has been acked. 140 | QuicPacketNumber largest_acked_packet_number_; 141 | 142 | // Track the largest packet number outstanding when a CWND cutback occurs. 143 | QuicPacketNumber largest_sent_at_last_cutback_; 144 | 145 | // Whether to use 4 packets as the actual min, but pace lower. 146 | bool min4_mode_; 147 | 148 | // Whether the last loss event caused us to exit slowstart. 149 | // Used for stats collection of slowstart_packets_lost 150 | bool last_cutback_exited_slowstart_; 151 | 152 | // When true, exit slow start with large cutback of congestion window. 153 | bool slow_start_large_reduction_; 154 | 155 | // When true, use unity pacing instead of PRR. 156 | bool no_prr_; 157 | 158 | // ACK counter for the Reno implementation. 159 | uint64_t num_acked_packets_; 160 | 161 | // Congestion window in bytes. 162 | QuicByteCount congestion_window_; 163 | 164 | // Minimum congestion window in bytes. 165 | QuicByteCount min_congestion_window_; 166 | 167 | // Maximum congestion window in bytes. 168 | QuicByteCount max_congestion_window_; 169 | 170 | // Slow start congestion window in bytes, aka ssthresh. 171 | QuicByteCount slowstart_threshold_; 172 | 173 | // Initial TCP congestion window in bytes. This variable can only be set when 174 | // this algorithm is created. 175 | const QuicByteCount initial_tcp_congestion_window_; 176 | 177 | // Initial maximum TCP congestion window in bytes. This variable can only be 178 | // set when this algorithm is created. 179 | const QuicByteCount initial_max_tcp_congestion_window_; 180 | 181 | // The minimum window when exiting slow start with large reduction. 182 | QuicByteCount min_slow_start_exit_window_; 183 | 184 | //cdg 185 | QuicByteCount shadow_congestion_window_; 186 | tcp_ca_state cong_state_; 187 | cdg_state cdg_state_; 188 | uint32_t backoff_factor_; 189 | uint32_t backoff_count_; 190 | uint32_t use_ineff_; 191 | uint32_t ineffective_hold_; 192 | struct minmax cdg_rtt_; 193 | struct minmax cdg_rtt_prev_; 194 | struct minmax cdg_gsum_; 195 | struct minmax gradients_[kRttWin]; 196 | bool gfilled_; 197 | int tail_; 198 | 199 | }; 200 | 201 | } // namespace quic 202 | 203 | #endif // QUICHE_QUIC_CORE_CONGESTION_CONTROL_TCP_CUBIC_SENDER_BYTES_H_ 204 | -------------------------------------------------------------------------------- /quic/model/cc-algo/cong_state.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | namespace quic{ 3 | /* 4 | * Sender's congestion state indicating normal or abnormal situations 5 | * in the last round of packets sent. The state is driven by the ACK 6 | * information and timer events. 7 | */ 8 | enum tcp_ca_state { 9 | /* 10 | * Nothing bad has been observed recently. 11 | * No apparent reordering, packet loss, or ECN marks. 12 | */ 13 | TCP_CA_Open = 0, 14 | #define TCPF_CA_Open (1< 4 | #include 5 | #include 6 | #include 7 | 8 | #include "gquiche/quic/core/congestion_control/rtt_stats.h" 9 | #include "gquiche/quic/core/quic_time.h" 10 | #include "gquiche/quic/core/quic_time_accumulator.h" 11 | #include "gquiche/quic/platform/api/quic_bug_tracker.h" 12 | #include "gquiche/quic/platform/api/quic_flag_utils.h" 13 | #include "gquiche/quic/platform/api/quic_flags.h" 14 | #include "gquiche/quic/platform/api/quic_logging.h" 15 | 16 | namespace quic{ 17 | namespace{ 18 | const QuicByteCount kDefaultMinimumCongestionWindow = 4 *kDefaultTCPMSS; 19 | const QuicTime::Delta kMinRTTWindowLength = QuicTime::Delta::FromSeconds(10); 20 | } 21 | template 22 | void addAndCheckOverflow(T1& value, const T1& toAdd) { 23 | if (std::numeric_limits::max() - toAdd < value) { 24 | // TODO: the error code is CWND_OVERFLOW but this function can totally be 25 | // used for inflight bytes. 26 | throw std::runtime_error("Overflow bytes in flight"); 27 | } 28 | value +=(toAdd); 29 | } 30 | template 31 | void subtractAndCheckUnderflow(T1& value, const T1& toSub) { 32 | if (value < toSub) { 33 | // TODO: wrong error code 34 | throw std::runtime_error("Underflow bytes in flight"); 35 | } 36 | value -=(toSub); 37 | } 38 | 39 | 40 | CopaSender::CopaSender(QuicTime now, 41 | const RttStats* rtt_stats, 42 | const QuicUnackedPacketMap* unacked_packets, 43 | QuicPacketCount initial_tcp_congestion_window, 44 | QuicPacketCount max_tcp_congestion_window, 45 | QuicRandom* random, 46 | QuicConnectionStats* stats): 47 | rtt_stats_(rtt_stats), 48 | unacked_packets_(unacked_packets), 49 | random_(random), 50 | stats_(stats), 51 | congestion_window_(initial_tcp_congestion_window * kDefaultTCPMSS), 52 | initial_congestion_window_(initial_tcp_congestion_window *kDefaultTCPMSS), 53 | max_congestion_window_(max_tcp_congestion_window * kDefaultTCPMSS), 54 | min_congestion_window_(kDefaultMinimumCongestionWindow), 55 | pacing_rate_(QuicBandwidth::Zero()), 56 | isSlowStart_(true), 57 | lastCwndDoubleTime_(QuicTime::Zero()), 58 | minRTTFilter_(kMinRTTWindowLength.ToMicroseconds(),QuicTime::Delta::Zero(),0), 59 | standingRTTFilter_(100000/*100 ms*/,QuicTime::Delta::Zero(),0){ 60 | if (stats_) { 61 | // Clear some startup stats if |stats_| has been used by another sender, 62 | // which happens e.g. when QuicConnection switch send algorithms. 63 | stats_->slowstart_count = 0; 64 | stats_->slowstart_duration = QuicTimeAccumulator(); 65 | } 66 | } 67 | CopaSender::~CopaSender(){} 68 | 69 | bool CopaSender::InSlowStart() const{ 70 | return isSlowStart_; 71 | } 72 | bool CopaSender::InRecovery() const{ 73 | return largest_acked_packet_number_.IsInitialized() && 74 | largest_sent_at_last_cutback_.IsInitialized() && 75 | largest_acked_packet_number_ <= largest_sent_at_last_cutback_; 76 | } 77 | bool CopaSender::ShouldSendProbingPacket() const{ 78 | return false; 79 | } 80 | void CopaSender::SetInitialCongestionWindowInPackets(QuicPacketCount congestion_window){ 81 | if(isSlowStart_){ 82 | initial_congestion_window_ = congestion_window * kDefaultTCPMSS; 83 | congestion_window_ = congestion_window * kDefaultTCPMSS; 84 | } 85 | } 86 | 87 | void CopaSender::OnCongestionEvent(bool rtt_updated, 88 | QuicByteCount prior_in_flight, 89 | QuicTime event_time, 90 | const AckedPacketVector& acked_packets, 91 | const LostPacketVector& lost_packets){ 92 | for (const LostPacket& lost_packet : lost_packets) { 93 | OnPacketLost(lost_packet.packet_number, lost_packet.bytes_lost, 94 | prior_in_flight); 95 | } 96 | OnPacketAcked(acked_packets, 97 | prior_in_flight, event_time); 98 | } 99 | void CopaSender::OnPacketSent(QuicTime sent_time, 100 | QuicByteCount bytes_in_flight, 101 | QuicPacketNumber packet_number, 102 | QuicByteCount bytes, 103 | HasRetransmittableData is_retransmittable){ 104 | QUICHE_DCHECK(!largest_sent_packet_number_.IsInitialized() || 105 | largest_sent_packet_number_ < packet_number); 106 | largest_sent_packet_number_ = packet_number; 107 | } 108 | bool CopaSender::CanSend(QuicByteCount bytes_in_flight){ 109 | return bytes_in_flightSmoothedOrInitialRtt(); 113 | const QuicBandwidth bandwidth = 114 | QuicBandwidth::FromBytesAndTimeDelta(GetCongestionWindow(), srtt); 115 | return bandwidth * (InSlowStart() ? 2 : (InRecovery() ? 1 : 1.25)); 116 | } 117 | QuicBandwidth CopaSender::BandwidthEstimate() const { 118 | QuicTime::Delta srtt = rtt_stats_->smoothed_rtt(); 119 | if (srtt.IsZero()) { 120 | // If we haven't measured an rtt, the bandwidth estimate is unknown. 121 | return QuicBandwidth::Zero(); 122 | } 123 | return QuicBandwidth::FromBytesAndTimeDelta(GetCongestionWindow(), srtt); 124 | } 125 | QuicByteCount CopaSender::GetCongestionWindow() const { 126 | return congestion_window_; 127 | } 128 | QuicByteCount CopaSender::GetSlowStartThreshold() const{ 129 | return 0; 130 | } 131 | CongestionControlType CopaSender::GetCongestionControlType() const{ 132 | return (CongestionControlType)kCopa; 133 | } 134 | std::string CopaSender::GetDebugState() const{ 135 | return "copa"; 136 | } 137 | void CopaSender::OnPacketLost(QuicPacketNumber packet_number, 138 | QuicByteCount lost_bytes, 139 | QuicByteCount prior_in_flight){ 140 | if (largest_sent_at_last_cutback_.IsInitialized() &&packet_number <= largest_sent_at_last_cutback_) { 141 | return; 142 | } 143 | largest_sent_at_last_cutback_=largest_sent_packet_number_; 144 | } 145 | void CopaSender::OnPacketAcked(const AckedPacketVector&acked_packets, 146 | QuicByteCount prior_in_flight, 147 | QuicTime event_time){ 148 | for (const AckedPacket acked_packet : acked_packets){ 149 | largest_acked_packet_number_.UpdateMax(acked_packet.packet_number); 150 | } 151 | QuicTime::Delta wall_time=event_time-QuicTime::Zero(); 152 | QuicTime::Delta lrtt=rtt_stats_->latest_rtt(); 153 | QuicTime::Delta srtt = rtt_stats_->smoothed_rtt(); 154 | minRTTFilter_.Update(lrtt,wall_time.ToMicroseconds()); 155 | auto rttMin = minRTTFilter_.GetBest(); 156 | standingRTTFilter_.SetWindowLength(srtt.ToMicroseconds()/ 2); 157 | standingRTTFilter_.Update(lrtt,wall_time.ToMicroseconds()); 158 | auto rttStanding= standingRTTFilter_.GetBest(); 159 | 160 | 161 | int64_t delayInMicroSec =lrtt.ToMicroseconds()- rttMin.ToMicroseconds(); 162 | if (delayInMicroSec < 0) { 163 | //LOG(ERROR) << __func__ 164 | // << "delay negative, lrtt=" << conn_.lossState.lrtt.count() 165 | // << " rttMin=" << rttMin.count() << " " << conn_; 166 | QUICHE_CHECK(0); 167 | return; 168 | } 169 | if (rttStanding.IsZero()) { 170 | //LOG(ERROR) << __func__ << "rttStandingMicroSec zero, lrtt = " 171 | // << conn_.lossState.lrtt.count() << " rttMin=" << rttMin.count() 172 | // << " " << conn_; 173 | QUICHE_CHECK(0); 174 | return; 175 | } 176 | 177 | bool increaseCwnd = false; 178 | if (delayInMicroSec == 0) { 179 | // taking care of inf targetRate case here, this happens in beginning where 180 | // we do want to increase cwnd 181 | increaseCwnd = true; 182 | } else { 183 | int64_t targetRate = (1.0 * kDefaultTCPMSS * 1000000) / 184 | (latencyFactor_ * delayInMicroSec); 185 | int64_t currentRate = (1.0 * GetCongestionWindow() * 1000000) / rttStanding.ToMicroseconds(); 186 | 187 | //VLOG(10) << __func__ << " estimated target rate=" << targetRate 188 | // << " current rate=" << currentRate << " " << conn_; 189 | increaseCwnd = targetRate >= currentRate; 190 | } 191 | 192 | if (!(increaseCwnd && isSlowStart_)) { 193 | // Update direction except for the case where we are in slow start mode, 194 | CheckAndUpdateDirection(event_time); 195 | } 196 | 197 | if (increaseCwnd) { 198 | if (isSlowStart_) { 199 | // When a flow starts, Copa performs slow-start where 200 | // cwnd doubles once per RTT until current rate exceeds target rate". 201 | if (!lastCwndDoubleTime_.IsInitialized()) { 202 | lastCwndDoubleTime_ =event_time; 203 | } else if ((event_time - lastCwndDoubleTime_)>srtt) { 204 | QUICHE_DLOG(INFO)<< __func__ << " doubling cwnd per RTT from=" << congestion_window_ 205 | << " due to slow start"; 206 | addAndCheckOverflow(congestion_window_, congestion_window_); 207 | lastCwndDoubleTime_ =event_time; 208 | } 209 | } else { 210 | if (velocityState_.direction != VelocityState::Direction::Up && 211 | velocityState_.velocity > 1.0) { 212 | // if our current rate is much different than target, we double v every 213 | // RTT. That could result in a high v at some point in time. If we 214 | // detect a sudden direction change here, while v is still very high but 215 | // meant for opposite direction, we should reset it to 1. 216 | ChangeDirection(VelocityState::Direction::Up, event_time); 217 | } 218 | uint64_t addition = (acked_packets.size()*kDefaultTCPMSS * 219 | kDefaultTCPMSS* velocityState_.velocity) / 220 | (latencyFactor_ * congestion_window_); 221 | QUICHE_DLOG(INFO)<< __func__ << " increasing cwnd from=" << congestion_window_ << " by " 222 | << addition; 223 | addAndCheckOverflow(congestion_window_, addition); 224 | } 225 | } else { 226 | if (velocityState_.direction != VelocityState::Direction::Down && 227 | velocityState_.velocity > 1.0) { 228 | // if our current rate is much different than target, we double v every 229 | // RTT. That could result in a high v at some point in time. If we detect 230 | // a sudden direction change here, while v is still very high but meant 231 | // for opposite direction, we should reset it to 1. 232 | ChangeDirection(VelocityState::Direction::Down, event_time); 233 | } 234 | uint64_t reduction = (acked_packets.size() *kDefaultTCPMSS* 235 | kDefaultTCPMSS * velocityState_.velocity) / 236 | (latencyFactor_ * congestion_window_); 237 | QUICHE_DLOG(INFO)<< __func__ << " decreasing cwnd from=" << congestion_window_ << " by " 238 | << reduction; 239 | isSlowStart_ = false; 240 | subtractAndCheckUnderflow( 241 | congestion_window_, 242 | std::min( 243 | reduction, 244 | congestion_window_ -min_congestion_window_)); 245 | } 246 | } 247 | void CopaSender::CheckAndUpdateDirection(const QuicTime ackTime){ 248 | if (!velocityState_.lastCwndRecordTime.IsInitialized()) { 249 | velocityState_.lastCwndRecordTime = ackTime; 250 | velocityState_.lastRecordedCwndBytes = GetCongestionWindow(); 251 | return; 252 | } 253 | QuicTime::Delta srtt = rtt_stats_->smoothed_rtt(); 254 | auto elapsed_time = ackTime - velocityState_.lastCwndRecordTime; 255 | 256 | 257 | if (elapsed_time >= srtt) { 258 | auto newDirection = GetCongestionWindow() > velocityState_.lastRecordedCwndBytes 259 | ? VelocityState::Direction::Up 260 | : VelocityState::Direction::Down; 261 | if (newDirection != velocityState_.direction) { 262 | // if direction changes, change velocity to 1 263 | velocityState_.velocity = 1; 264 | velocityState_.numTimesDirectionSame = 0; 265 | } else { 266 | velocityState_.numTimesDirectionSame++; 267 | if (velocityState_.numTimesDirectionSame >= 3) { 268 | velocityState_.velocity = 2 * velocityState_.velocity; 269 | } 270 | } 271 | /*VLOG(10) << __func__ << " updated direction from " 272 | << velocityState_.direction << " to " << newDirection 273 | << " velocityState_.numTimesDirectionSame " 274 | << velocityState_.numTimesDirectionSame << " velocity " 275 | << velocityState_.velocity << " " << conn_;*/ 276 | velocityState_.direction = newDirection; 277 | velocityState_.lastCwndRecordTime = ackTime; 278 | velocityState_.lastRecordedCwndBytes = GetCongestionWindow(); 279 | } 280 | } 281 | void CopaSender::ChangeDirection( 282 | VelocityState::Direction newDirection, 283 | const QuicTime ackTime) { 284 | if (velocityState_.direction == newDirection) { 285 | return; 286 | } 287 | //VLOG(10) << __func__ << " Suddenly direction change to " << newDirection 288 | // << " " << conn_; 289 | velocityState_.direction = newDirection; 290 | velocityState_.velocity = 1; 291 | velocityState_.numTimesDirectionSame = 0; 292 | velocityState_.lastCwndRecordTime = ackTime; 293 | velocityState_.lastRecordedCwndBytes =GetCongestionWindow() ; 294 | } 295 | } -------------------------------------------------------------------------------- /quic/model/cc-algo/copa_sender.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | /* 3 | Copa: Practical Delay-Based Congestion Control for the Internet 4 | The implementation is copied from mvfst(https://github.com/facebookincubator/mvfst/). 5 | */ 6 | #include 7 | #include 8 | #include 9 | 10 | #include "gquiche/quic/core/congestion_control/bandwidth_sampler.h" 11 | #include "gquiche/quic/core/congestion_control/send_algorithm_interface.h" 12 | #include "gquiche/quic/core/congestion_control/windowed_filter.h" 13 | #include "gquiche/quic/core/crypto/quic_random.h" 14 | #include "gquiche/quic/core/quic_bandwidth.h" 15 | #include "gquiche/quic/core/quic_packet_number.h" 16 | #include "gquiche/quic/core/quic_packets.h" 17 | #include "gquiche/quic/core/quic_time.h" 18 | #include "gquiche/quic/core/quic_unacked_packet_map.h" 19 | #include "gquiche/quic/platform/api/quic_export.h" 20 | #include "gquiche/quic/platform/api/quic_flags.h" 21 | namespace quic{ 22 | class RttStats; 23 | QUIC_EXPORT_PRIVATE class CopaSender:public SendAlgorithmInterface{ 24 | public: 25 | CopaSender(QuicTime now, 26 | const RttStats* rtt_stats, 27 | const QuicUnackedPacketMap* unacked_packets, 28 | QuicPacketCount initial_tcp_congestion_window, 29 | QuicPacketCount max_tcp_congestion_window, 30 | QuicRandom* random, 31 | QuicConnectionStats* stats); 32 | CopaSender(const CopaSender&) = delete; 33 | CopaSender& operator=(const CopaSender&) = delete; 34 | ~CopaSender() override; 35 | 36 | // Start implementation of SendAlgorithmInterface. 37 | bool InSlowStart() const override; 38 | bool InRecovery() const override; 39 | bool ShouldSendProbingPacket() const override; 40 | 41 | void SetFromConfig(const QuicConfig& config, 42 | Perspective perspective) override{} 43 | void ApplyConnectionOptions(const QuicTagVector& connection_options) override{} 44 | 45 | void AdjustNetworkParameters(const NetworkParams& params) override{} 46 | void SetInitialCongestionWindowInPackets( 47 | QuicPacketCount congestion_window) override; 48 | void OnCongestionEvent(bool rtt_updated, 49 | QuicByteCount prior_in_flight, 50 | QuicTime event_time, 51 | const AckedPacketVector& acked_packets, 52 | const LostPacketVector& lost_packets) override; 53 | void OnPacketSent(QuicTime sent_time, 54 | QuicByteCount bytes_in_flight, 55 | QuicPacketNumber packet_number, 56 | QuicByteCount bytes, 57 | HasRetransmittableData is_retransmittable) override; 58 | void OnPacketNeutered(QuicPacketNumber packet_number) override{} 59 | void OnRetransmissionTimeout(bool /*packets_retransmitted*/) override {} 60 | void OnConnectionMigration() override {} 61 | bool CanSend(QuicByteCount bytes_in_flight) override; 62 | QuicBandwidth PacingRate(QuicByteCount bytes_in_flight) const override; 63 | QuicBandwidth BandwidthEstimate() const override; 64 | QuicByteCount GetCongestionWindow() const override; 65 | QuicByteCount GetSlowStartThreshold() const override; 66 | CongestionControlType GetCongestionControlType() const override; 67 | std::string GetDebugState() const override; 68 | void OnApplicationLimited(QuicByteCount bytes_in_flight) override{} 69 | void PopulateConnectionStats(QuicConnectionStats* stats) const override{} 70 | // End implementation of SendAlgorithmInterface. 71 | 72 | private: 73 | struct VelocityState { 74 | uint64_t velocity{1}; 75 | enum Direction { 76 | None, 77 | Up, // cwnd is increasing 78 | Down, // cwnd is decreasing 79 | }; 80 | Direction direction{None}; 81 | // number of rtts direction has remained same 82 | uint64_t numTimesDirectionSame{0}; 83 | // updated every srtt 84 | QuicByteCount lastRecordedCwndBytes; 85 | QuicTime lastCwndRecordTime{QuicTime::Zero()}; 86 | }; 87 | void OnPacketLost(QuicPacketNumber largest_loss, 88 | QuicByteCount lost_bytes, 89 | QuicByteCount prior_in_flight); 90 | void OnPacketAcked(const AckedPacketVector&acked_packets, 91 | QuicByteCount prior_in_flight, 92 | QuicTime event_time); 93 | void CheckAndUpdateDirection(const QuicTime ackTime); 94 | void ChangeDirection(VelocityState::Direction newDirection, 95 | const QuicTime ackTime); 96 | // Determines the appropriate pacing rate for the connection. 97 | void CalculatePacingRate(); 98 | 99 | const RttStats* rtt_stats_; 100 | const QuicUnackedPacketMap* unacked_packets_; 101 | QuicRandom* random_; 102 | QuicConnectionStats* stats_; 103 | 104 | // Track the largest packet that has been sent. 105 | QuicPacketNumber largest_sent_packet_number_; 106 | // Track the largest packet that has been acked. 107 | QuicPacketNumber largest_acked_packet_number_; 108 | // Track the largest packet number outstanding when a CWND cutback occurs. 109 | QuicPacketNumber largest_sent_at_last_cutback_; 110 | // The maximum allowed number of bytes in flight. 111 | QuicByteCount congestion_window_; 112 | // The initial value of the |congestion_window_|. 113 | QuicByteCount initial_congestion_window_; 114 | // The largest value the |congestion_window_| can achieve. 115 | QuicByteCount max_congestion_window_; 116 | // The smallest value the |congestion_window_| can achieve. 117 | QuicByteCount min_congestion_window_; 118 | // The current pacing rate of the connection. 119 | QuicBandwidth pacing_rate_; 120 | bool isSlowStart_; 121 | QuicTime lastCwndDoubleTime_; 122 | using RTTFilter=WindowedFilter,uint64_t,uint64_t> ; 123 | RTTFilter minRTTFilter_; 124 | RTTFilter standingRTTFilter_; 125 | VelocityState velocityState_; 126 | /** 127 | * latencyFactor_ determines how latency sensitive the algorithm is. Lower 128 | * means it will maximime throughput at expense of delay. Higher value means 129 | * it will minimize delay at expense of throughput. 130 | */ 131 | double latencyFactor_{0.50}; 132 | }; 133 | } -------------------------------------------------------------------------------- /quic/model/cc-algo/vegas_sender.cc: -------------------------------------------------------------------------------- 1 | #include "vegas_sender.h" 2 | #include "../ns3-quic-private.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "gquiche/quic/core/congestion_control/rtt_stats.h" 9 | #include "gquiche/quic/core/quic_time.h" 10 | #include "gquiche/quic/core/quic_time_accumulator.h" 11 | #include "gquiche/quic/platform/api/quic_bug_tracker.h" 12 | #include "gquiche/quic/platform/api/quic_flag_utils.h" 13 | #include "gquiche/quic/platform/api/quic_flags.h" 14 | #include "gquiche/quic/platform/api/quic_logging.h" 15 | 16 | namespace quic{ 17 | namespace{ 18 | const QuicByteCount kDefaultMinimumCongestionWindow = 4 *kDefaultTCPMSS; 19 | const QuicByteCount kAlphaCongestionWindow=2*kDefaultTCPMSS; 20 | const QuicByteCount kBetaCongestionWindow=4*kDefaultTCPMSS; 21 | const QuicByteCount kGammaCongestionWindow=1*kDefaultTCPMSS; 22 | const QuicTime::Delta kMinRTTWindowLength = QuicTime::Delta::FromSeconds(10); 23 | } 24 | 25 | VegasSender::VegasSender(QuicTime now, 26 | const RttStats* rtt_stats, 27 | const QuicUnackedPacketMap* unacked_packets, 28 | QuicPacketCount initial_tcp_congestion_window, 29 | QuicPacketCount max_tcp_congestion_window, 30 | QuicRandom* random, 31 | QuicConnectionStats* stats): 32 | rtt_stats_(rtt_stats), 33 | unacked_packets_(unacked_packets), 34 | random_(random), 35 | stats_(stats), 36 | congestion_window_(initial_tcp_congestion_window * kDefaultTCPMSS), 37 | initial_congestion_window_(initial_tcp_congestion_window *kDefaultTCPMSS), 38 | max_congestion_window_(max_tcp_congestion_window * kDefaultTCPMSS), 39 | min_congestion_window_(kDefaultMinimumCongestionWindow), 40 | slowstart_threshold_(max_tcp_congestion_window * kDefaultTCPMSS), 41 | pacing_rate_(QuicBandwidth::Zero()), 42 | baseRTTFilter_(kMinRTTWindowLength.ToMicroseconds(),QuicTime::Delta::Zero(),0), 43 | min_rtt_(QuicTime::Delta::Infinite()), 44 | rtt_count_(0), 45 | num_acked_packets_(0), 46 | vegas_mode_(true){ 47 | if (stats_) { 48 | // Clear some startup stats if |stats_| has been used by another sender, 49 | // which happens e.g. when QuicConnection switch send algorithms. 50 | stats_->slowstart_count = 0; 51 | stats_->slowstart_duration = QuicTimeAccumulator(); 52 | } 53 | } 54 | VegasSender::~VegasSender(){} 55 | 56 | bool VegasSender::InSlowStart() const{ 57 | return GetCongestionWindow() < GetSlowStartThreshold(); 58 | } 59 | bool VegasSender::InRecovery() const{ 60 | return largest_acked_packet_number_.IsInitialized() && 61 | largest_sent_at_last_cutback_.IsInitialized() && 62 | largest_acked_packet_number_ <= largest_sent_at_last_cutback_; 63 | } 64 | bool VegasSender::ShouldSendProbingPacket() const{ 65 | return false; 66 | } 67 | void VegasSender::SetInitialCongestionWindowInPackets(QuicPacketCount congestion_window){ 68 | if(InSlowStart()){ 69 | initial_congestion_window_ = congestion_window * kDefaultTCPMSS; 70 | congestion_window_ = congestion_window * kDefaultTCPMSS; 71 | } 72 | } 73 | 74 | void VegasSender::OnCongestionEvent(bool rtt_updated, 75 | QuicByteCount prior_in_flight, 76 | QuicTime event_time, 77 | const AckedPacketVector& acked_packets, 78 | const LostPacketVector& lost_packets){ 79 | if(acked_packets.size()>0){ 80 | auto vrtt=rtt_stats_->latest_rtt()+QuicTime::Delta::FromMicroseconds(1); 81 | QuicTime::Delta wall_time=event_time-QuicTime::Zero(); 82 | baseRTTFilter_.Update(vrtt,wall_time.ToMicroseconds()); 83 | if(min_rtt_>vrtt){ 84 | min_rtt_=vrtt; 85 | } 86 | rtt_count_++; 87 | } 88 | bool before=InRecovery(); 89 | 90 | for (const LostPacket& lost_packet : lost_packets) { 91 | OnPacketLost(lost_packet.packet_number, lost_packet.bytes_lost, 92 | prior_in_flight); 93 | } 94 | for (const AckedPacket& acked_packet : acked_packets) { 95 | OnPacketAcked(acked_packet.packet_number, acked_packet.bytes_acked, 96 | prior_in_flight, event_time); 97 | } 98 | if(InRecovery()!=before){ 99 | if(InRecovery()){ 100 | //vegas_disable 101 | vegas_mode_=false; 102 | }else{ 103 | //vegas_enable 104 | vegas_mode_=true; 105 | beg_send_next_=largest_sent_packet_number_; 106 | min_rtt_=QuicTime::Delta::Infinite(); 107 | rtt_count_=0; 108 | } 109 | } 110 | } 111 | void VegasSender::OnPacketSent(QuicTime sent_time, 112 | QuicByteCount bytes_in_flight, 113 | QuicPacketNumber packet_number, 114 | QuicByteCount bytes, 115 | HasRetransmittableData is_retransmittable){ 116 | QUICHE_DCHECK(!largest_sent_packet_number_.IsInitialized() || 117 | largest_sent_packet_number_ < packet_number); 118 | largest_sent_packet_number_ = packet_number; 119 | if(!beg_send_next_.IsInitialized()){ 120 | beg_send_next_=largest_sent_packet_number_; 121 | } 122 | } 123 | void VegasSender::OnRetransmissionTimeout(bool /*packets_retransmitted*/){ 124 | 125 | } 126 | bool VegasSender::CanSend(QuicByteCount bytes_in_flight){ 127 | return bytes_in_flightSmoothedOrInitialRtt(); 131 | const QuicBandwidth bandwidth = 132 | QuicBandwidth::FromBytesAndTimeDelta(GetCongestionWindow(), srtt); 133 | return bandwidth * (InSlowStart() ? 2 : (InRecovery() ? 1 : 1.25)); 134 | } 135 | QuicBandwidth VegasSender::BandwidthEstimate() const { 136 | QuicTime::Delta srtt = rtt_stats_->smoothed_rtt(); 137 | if (srtt.IsZero()) { 138 | // If we haven't measured an rtt, the bandwidth estimate is unknown. 139 | return QuicBandwidth::Zero(); 140 | } 141 | return QuicBandwidth::FromBytesAndTimeDelta(GetCongestionWindow(), srtt); 142 | } 143 | QuicByteCount VegasSender::GetCongestionWindow() const { 144 | return congestion_window_; 145 | } 146 | QuicByteCount VegasSender::GetSlowStartThreshold() const{ 147 | return slowstart_threshold_; 148 | } 149 | CongestionControlType VegasSender::GetCongestionControlType() const{ 150 | return (CongestionControlType)kVegas; 151 | } 152 | std::string VegasSender::GetDebugState() const{ 153 | return "copa"; 154 | } 155 | void VegasSender::OnPacketLost(QuicPacketNumber packet_number, 156 | QuicByteCount lost_bytes, 157 | QuicByteCount prior_in_flight){ 158 | if (largest_sent_at_last_cutback_.IsInitialized() &&packet_number <= largest_sent_at_last_cutback_) { 159 | return; 160 | } 161 | congestion_window_=congestion_window_/2; 162 | congestion_window_=std::max(congestion_window_,min_congestion_window_); 163 | slowstart_threshold_ = congestion_window_; 164 | largest_sent_at_last_cutback_=largest_sent_packet_number_; 165 | num_acked_packets_ = 0; 166 | } 167 | void VegasSender::OnPacketAcked(QuicPacketNumber acked_packet_number, 168 | QuicByteCount acked_bytes, 169 | QuicByteCount prior_in_flight, 170 | QuicTime event_time){ 171 | largest_acked_packet_number_.UpdateMax(acked_packet_number); 172 | if(!vegas_mode_){ 173 | //reno mode 174 | IncreaseCongestionWindowAsReno(); 175 | return ; 176 | } 177 | QUICHE_CHECK(beg_send_next_.IsInitialized()); 178 | if(acked_packet_number>=beg_send_next_){ 179 | beg_send_next_=largest_sent_packet_number_; 180 | if(rtt_count_<=2){ 181 | IncreaseCongestionWindowAsReno(); 182 | }else{ 183 | QuicTime::Delta base_rtt=baseRTTFilter_.GetBest(); 184 | QuicByteCount target_cwnd=congestion_window_*base_rtt.ToMicroseconds()/min_rtt_.ToMicroseconds(); 185 | target_cwnd=((target_cwnd+kDefaultTCPMSS-1)/kDefaultTCPMSS)*kDefaultTCPMSS; 186 | QUICHE_CHECK(min_rtt_>=base_rtt); 187 | QuicByteCount diff=congestion_window_*(min_rtt_.ToMicroseconds()-base_rtt.ToMicroseconds())/base_rtt.ToMicroseconds(); 188 | if(diff>kGammaCongestionWindow&&InSlowStart()){ 189 | /* Going too fast. Time to slow down 190 | * and switch to congestion avoidance. 191 | */ 192 | 193 | /* Set cwnd to match the actual rate 194 | * exactly: 195 | * cwnd = (actual rate) * baseRTT 196 | * Then we add 1 because the integer 197 | * truncation robs us of full link 198 | * utilization. 199 | */ 200 | congestion_window_=std::min(congestion_window_,target_cwnd); 201 | slowstart_threshold_=congestion_window_; 202 | }else if(InSlowStart()){ 203 | congestion_window_ += kDefaultTCPMSS; 204 | }else{ 205 | if(diff>kBetaCongestionWindow){ 206 | if(congestion_window_>min_congestion_window_){ 207 | congestion_window_-=kDefaultTCPMSS; 208 | } 209 | }else if(diff=congestion_window_) { 229 | congestion_window_ += kDefaultTCPMSS; 230 | num_acked_packets_ = 0; 231 | } 232 | } 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /quic/model/cc-algo/vegas_sender.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | #include "gquiche/quic/core/congestion_control/bandwidth_sampler.h" 7 | #include "gquiche/quic/core/congestion_control/send_algorithm_interface.h" 8 | #include "gquiche/quic/core/congestion_control/windowed_filter.h" 9 | #include "gquiche/quic/core/crypto/quic_random.h" 10 | #include "gquiche/quic/core/quic_bandwidth.h" 11 | #include "gquiche/quic/core/quic_packet_number.h" 12 | #include "gquiche/quic/core/quic_packets.h" 13 | #include "gquiche/quic/core/quic_time.h" 14 | #include "gquiche/quic/core/quic_unacked_packet_map.h" 15 | #include "gquiche/quic/platform/api/quic_export.h" 16 | #include "gquiche/quic/platform/api/quic_flags.h" 17 | namespace quic{ 18 | class RttStats; 19 | QUIC_EXPORT_PRIVATE class VegasSender:public SendAlgorithmInterface{ 20 | public: 21 | VegasSender(QuicTime now, 22 | const RttStats* rtt_stats, 23 | const QuicUnackedPacketMap* unacked_packets, 24 | QuicPacketCount initial_tcp_congestion_window, 25 | QuicPacketCount max_tcp_congestion_window, 26 | QuicRandom* random, 27 | QuicConnectionStats* stats); 28 | VegasSender(const VegasSender&) = delete; 29 | VegasSender& operator=(const VegasSender&) = delete; 30 | ~VegasSender() override; 31 | 32 | // Start implementation of SendAlgorithmInterface. 33 | bool InSlowStart() const override; 34 | bool InRecovery() const override; 35 | bool ShouldSendProbingPacket() const override; 36 | 37 | void SetFromConfig(const QuicConfig& config, 38 | Perspective perspective) override{} 39 | void ApplyConnectionOptions(const QuicTagVector& connection_options) override{} 40 | 41 | void AdjustNetworkParameters(const NetworkParams& params) override{} 42 | void SetInitialCongestionWindowInPackets( 43 | QuicPacketCount congestion_window) override; 44 | void OnCongestionEvent(bool rtt_updated, 45 | QuicByteCount prior_in_flight, 46 | QuicTime event_time, 47 | const AckedPacketVector& acked_packets, 48 | const LostPacketVector& lost_packets) override; 49 | void OnPacketSent(QuicTime sent_time, 50 | QuicByteCount bytes_in_flight, 51 | QuicPacketNumber packet_number, 52 | QuicByteCount bytes, 53 | HasRetransmittableData is_retransmittable) override; 54 | void OnPacketNeutered(QuicPacketNumber packet_number) override{} 55 | void OnRetransmissionTimeout(bool /*packets_retransmitted*/) override; 56 | void OnConnectionMigration() override {} 57 | bool CanSend(QuicByteCount bytes_in_flight) override; 58 | QuicBandwidth PacingRate(QuicByteCount bytes_in_flight) const override; 59 | QuicBandwidth BandwidthEstimate() const override; 60 | QuicByteCount GetCongestionWindow() const override; 61 | QuicByteCount GetSlowStartThreshold() const override; 62 | CongestionControlType GetCongestionControlType() const override; 63 | std::string GetDebugState() const override; 64 | void OnApplicationLimited(QuicByteCount bytes_in_flight) override{} 65 | void PopulateConnectionStats(QuicConnectionStats* stats) const override{} 66 | // End implementation of SendAlgorithmInterface. 67 | 68 | private: 69 | 70 | void OnPacketLost(QuicPacketNumber largest_loss, 71 | QuicByteCount lost_bytes, 72 | QuicByteCount prior_in_flight); 73 | void OnPacketAcked(QuicPacketNumber acked_packet_number, 74 | QuicByteCount acked_bytes, 75 | QuicByteCount prior_in_flight, 76 | QuicTime event_time); 77 | void IncreaseCongestionWindowAsReno(); 78 | // Determines the appropriate pacing rate for the connection. 79 | void CalculatePacingRate(); 80 | 81 | const RttStats* rtt_stats_; 82 | const QuicUnackedPacketMap* unacked_packets_; 83 | QuicRandom* random_; 84 | QuicConnectionStats* stats_; 85 | 86 | // Track the largest packet that has been sent. 87 | QuicPacketNumber largest_sent_packet_number_; 88 | // Track the largest packet that has been acked. 89 | QuicPacketNumber largest_acked_packet_number_; 90 | // Track the largest packet number outstanding when a CWND cutback occurs. 91 | QuicPacketNumber largest_sent_at_last_cutback_; 92 | // The maximum allowed number of bytes in flight. 93 | QuicByteCount congestion_window_; 94 | // The initial value of the |congestion_window_|. 95 | QuicByteCount initial_congestion_window_; 96 | // The largest value the |congestion_window_| can achieve. 97 | QuicByteCount max_congestion_window_; 98 | // The smallest value the |congestion_window_| can achieve. 99 | QuicByteCount min_congestion_window_; 100 | // Slow start congestion window in bytes, aka ssthresh. 101 | QuicByteCount slowstart_threshold_; 102 | // The current pacing rate of the connection. 103 | QuicBandwidth pacing_rate_; 104 | using RTTFilter=WindowedFilter,uint64_t,uint64_t> ; 105 | RTTFilter baseRTTFilter_; 106 | QuicTime::Delta min_rtt_; 107 | int32_t rtt_count_; 108 | QuicPacketNumber beg_send_next_; 109 | uint64_t num_acked_packets_; 110 | bool vegas_mode_; 111 | 112 | }; 113 | } -------------------------------------------------------------------------------- /quic/model/ns3-client-network-helper.cc: -------------------------------------------------------------------------------- 1 | #include "ns3-client-network-helper.h" 2 | #include "ns3-quic-poll-server.h" 3 | #include "ns3/assert.h" 4 | namespace quic{ 5 | Ns3ClientNetworkHelper::Ns3ClientNetworkHelper(Ns3QuicPollServer *poller,QuicClientBase* client): 6 | poller_(poller),client_(client){} 7 | Ns3ClientNetworkHelper::~Ns3ClientNetworkHelper(){ 8 | if (client_->connected()) { 9 | client_->session()->connection()->CloseConnection( 10 | QUIC_PEER_GOING_AWAY, "Client being torn down", 11 | ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); 12 | } 13 | CleanUpAllUDPSockets(); 14 | } 15 | void Ns3ClientNetworkHelper::RunEventLoop(){ 16 | NS_ASSERT_MSG(0,"run event loop should not be called"); 17 | return; 18 | } 19 | bool Ns3ClientNetworkHelper::CreateUDPSocketAndBind(QuicSocketAddress server_address, 20 | QuicIpAddress bind_to_address, 21 | int bind_to_port){ 22 | bool ret=poller_->CreateUDPSocketAndBind(server_address,bind_to_address,bind_to_port); 23 | if(ret){ 24 | poller_->RegisterFD(this); 25 | } 26 | return ret; 27 | } 28 | void Ns3ClientNetworkHelper::CleanUpAllUDPSockets(){ 29 | poller_->UnregisterFD(this); 30 | } 31 | QuicSocketAddress Ns3ClientNetworkHelper::GetLatestClientAddress() const{ 32 | return poller_->GetLatestClientAddress(); 33 | } 34 | QuicPacketWriter* Ns3ClientNetworkHelper::CreateQuicPacketWriter(){ 35 | return poller_->CreateQuicPacketWriter(); 36 | } 37 | void Ns3ClientNetworkHelper::ProcessPacket(const QuicSocketAddress& self_address, 38 | const QuicSocketAddress& peer_address, 39 | const QuicReceivedPacket& packet){ 40 | client_->session()->ProcessUdpPacket(self_address, peer_address, packet); 41 | } 42 | void Ns3ClientNetworkHelper::OnRegistration(){ 43 | 44 | } 45 | void Ns3ClientNetworkHelper::OnUnregistration(){ 46 | 47 | } 48 | void Ns3ClientNetworkHelper::OnShutdown(){ 49 | 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /quic/model/ns3-client-network-helper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "gquiche/quic/core/quic_packets.h" 3 | #include "gquiche/quic/platform/api/quic_socket_address.h" 4 | #include "gquiche/quic/tools/quic_client_base.h" 5 | #include "gquiche/quic/core/quic_packet_writer.h" 6 | #include "ns3-quic-poll-server.h" 7 | namespace quic{ 8 | class Ns3QuicPollServer; 9 | class Ns3ClientNetworkHelper:public QuicClientBase::NetworkHelper,public Ns3PacketInCallback{ 10 | public: 11 | Ns3ClientNetworkHelper(Ns3QuicPollServer *poller,QuicClientBase* client); 12 | ~Ns3ClientNetworkHelper() override; 13 | //from QuicClientBase::NetworkHelper 14 | void RunEventLoop() override; 15 | bool CreateUDPSocketAndBind(QuicSocketAddress server_address, 16 | QuicIpAddress bind_to_address, 17 | int bind_to_port) override; 18 | void CleanUpAllUDPSockets() override; 19 | QuicSocketAddress GetLatestClientAddress() const override; 20 | QuicPacketWriter* CreateQuicPacketWriter() override; 21 | //from Ns3PacketInCallback 22 | void ProcessPacket(const QuicSocketAddress& self_address, 23 | const QuicSocketAddress& peer_address, 24 | const QuicReceivedPacket& packet) override; 25 | void OnRegistration() override; 26 | void OnUnregistration() override; 27 | void OnShutdown() override; 28 | private: 29 | Ns3QuicPollServer *poller_=nullptr; 30 | QuicClientBase *client_=nullptr; 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /quic/model/ns3-packet-writer.cc: -------------------------------------------------------------------------------- 1 | #include "ns3-packet-writer.h" 2 | namespace quic{ 3 | Ns3PacketWriter::Ns3PacketWriter(Delegate *delegate):delegate_(delegate){} 4 | Ns3PacketWriter::~Ns3PacketWriter(){ 5 | delegate_->OnWriterDestroy(); 6 | } 7 | WriteResult Ns3PacketWriter::WritePacket(const char* buffer, 8 | size_t buf_len, 9 | const QuicIpAddress& self_address, 10 | const QuicSocketAddress& peer_address, 11 | PerPacketOptions* options){ 12 | int rc=delegate_->WritePacket(buffer,buf_len,self_address,peer_address); 13 | return WriteResult(WRITE_STATUS_OK, rc); 14 | } 15 | bool Ns3PacketWriter::IsWriteBlocked() const{ 16 | return write_blocked_; 17 | } 18 | void Ns3PacketWriter::SetWritable(){ 19 | write_blocked_ = false; 20 | } 21 | QuicByteCount Ns3PacketWriter::GetMaxPacketSize( 22 | const QuicSocketAddress& /*peer_address*/) const { 23 | return kMaxOutgoingPacketSize; 24 | } 25 | bool Ns3PacketWriter::SupportsReleaseTime() const { 26 | return false; 27 | } 28 | 29 | bool Ns3PacketWriter::IsBatchMode() const { 30 | return false; 31 | } 32 | QuicPacketBuffer Ns3PacketWriter::GetNextWriteLocation( 33 | const QuicIpAddress& /*self_address*/, 34 | const QuicSocketAddress& /*peer_address*/) { 35 | return {nullptr, nullptr}; 36 | } 37 | 38 | WriteResult Ns3PacketWriter::Flush() { 39 | return WriteResult(WRITE_STATUS_OK, 0); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /quic/model/ns3-packet-writer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "gquiche/quic/core/quic_packet_writer.h" 3 | namespace quic{ 4 | class Ns3PacketWriter: public QuicPacketWriter{ 5 | public: 6 | class Delegate{ 7 | public: 8 | virtual ~Delegate(){} 9 | //return write length 10 | virtual int WritePacket(const char* buffer, 11 | size_t buf_len, 12 | const QuicIpAddress& self_address, 13 | const QuicSocketAddress& peer_address)=0; 14 | virtual void OnWriterDestroy()=0; 15 | }; 16 | Ns3PacketWriter(Delegate *delegate); 17 | ~Ns3PacketWriter() override; 18 | // QuicPacketWriter 19 | WriteResult WritePacket(const char* buffer, 20 | size_t buf_len, 21 | const QuicIpAddress& self_address, 22 | const QuicSocketAddress& peer_address, 23 | PerPacketOptions* options) override; 24 | bool IsWriteBlocked() const override; 25 | void SetWritable() override; 26 | QuicByteCount GetMaxPacketSize( 27 | const QuicSocketAddress& peer_address) const override; 28 | bool SupportsReleaseTime() const override; 29 | bool IsBatchMode() const override; 30 | QuicPacketBuffer GetNextWriteLocation( 31 | const QuicIpAddress& self_address, 32 | const QuicSocketAddress& peer_address) override; 33 | WriteResult Flush() override; 34 | private: 35 | Delegate *delegate_=nullptr; 36 | bool write_blocked_=false; 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-addr-convert.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "ns3/inet-socket-address.h" 3 | #include "gquiche/quic/platform/api/quic_socket_address.h" 4 | namespace ns3{ 5 | quic::QuicSocketAddress GetQuicSocketAddr(const InetSocketAddress &addr); 6 | InetSocketAddress GetNs3SocketAddr(const quic::QuicSocketAddress &addr); 7 | } 8 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-addr-pair.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "ns3/inet-socket-address.h" 3 | namespace ns3{ 4 | struct Ns3QuicAddressPair{ 5 | Ns3QuicAddressPair(const InetSocketAddress &c,const InetSocketAddress & s): 6 | client_ip(c.GetIpv4().Get()), 7 | server_ip(s.GetIpv4().Get()), 8 | client_port(c.GetPort()), 9 | server_port(s.GetPort()){} 10 | uint32_t client_ip; 11 | uint32_t server_ip; 12 | uint16_t client_port; 13 | uint16_t server_port; 14 | bool operator < (const Ns3QuicAddressPair &o) const 15 | { 16 | return client_ip < o.client_ip||server_ip 2 | #include 3 | #include 4 | #include 5 | 6 | #include "gquiche/quic/platform/api/quic_logging.h" 7 | #include "gquiche/quic/core/quic_arena_scoped_ptr.h" 8 | 9 | 10 | #include "ns3/simulator.h" 11 | #include "ns3/log.h" 12 | #include "ns3/assert.h" 13 | #include "ns3-quic-alarm-engine.h" 14 | using namespace ns3; 15 | NS_LOG_COMPONENT_DEFINE("Ns3QuicAlarmEngine"); 16 | #define MOD_DEBUG 1 17 | namespace quic{ 18 | Ns3QuicAlarmEngine::Ns3QuicAlarmEngine(Perspective role): 19 | role_(role), 20 | visitor_(nullptr){} 21 | Ns3QuicAlarmEngine::~Ns3QuicAlarmEngine(){ 22 | Shutdown(); 23 | } 24 | void Ns3QuicAlarmEngine::Shutdown(){ 25 | TimeToAlarmCBMap::iterator erase_it; 26 | for(auto i=alarm_map_.begin();i!=alarm_map_.end();){ 27 | AlarmCB* cb = i->second; 28 | erase_it=i; 29 | i++; 30 | alarm_map_.erase(erase_it); 31 | all_alarms_.erase(cb); 32 | cb->OnShutdown(this); 33 | } 34 | } 35 | void Ns3QuicAlarmEngine::RegisterAlarm(int64_t timeout_us,AlarmCB* ac){ 36 | bool update=false; 37 | ns3::Time now=ns3::Simulator::Now(); 38 | int64_t now_us=now.GetMicroSeconds(); 39 | if(timeout_usfirst; 50 | if(timeout_usOnRegistration(alarm_iter,this); 58 | } 59 | if((!timer_.IsRunning())||update){ 60 | UpdateTimer(); 61 | } 62 | 63 | } 64 | void Ns3QuicAlarmEngine::UnregisterAlarm(const AlarmRegToken & iterator_token){ 65 | AlarmCB* cb = iterator_token->second; 66 | alarm_map_.erase(iterator_token); 67 | all_alarms_.erase(cb); 68 | cb->OnUnregistration(); 69 | } 70 | Ns3QuicAlarmEngine::AlarmRegToken Ns3QuicAlarmEngine::ReregisterAlarm(AlarmRegToken &iterator_token, int64_t timeout_us){ 71 | int64_t now_us=ns3::Simulator::Now().GetMicroSeconds(); 72 | AlarmCB* cb = iterator_token->second; 73 | int64_t last_us=iterator_token->first; 74 | alarm_map_.erase(iterator_token); 75 | NS_ASSERT(!alarm_map_.empty()); 76 | auto i=alarm_map_.begin(); 77 | int64_t next_timeout_us=i->first; 78 | #if (MOD_DEBUG) 79 | if(timeout_us<=now_us){ 80 | NS_LOG_FUNCTION(now_us<first; 99 | NS_ASSERT_MSG(future_us>=now_us,now_us<<":"< cbs; 108 | bool has_event=false; 109 | int64_t next_timeout_us=0; 110 | for(auto i=alarm_map_.begin();i!=alarm_map_.end();){ 111 | if(i->first>now_us){ 112 | break; 113 | } 114 | AlarmCB* cb = i->second; 115 | erase_it=i; 116 | i++; 117 | alarm_map_.erase(erase_it); 118 | all_alarms_.erase(cb); 119 | cbs.push_back(cb); 120 | has_event=true; 121 | } 122 | for(auto it=cbs.begin();it!=cbs.end();it++){ 123 | AlarmCB *cb=(*it); 124 | int c=0; 125 | do{ 126 | next_timeout_us=cb->OnAlarm(); 127 | c++; 128 | #if (MOD_DEBUG) 129 | if((next_timeout_us>0)&&(next_timeout_us<=now_us)){ 130 | NS_LOG_FUNCTION(now_us<0)&&(next_timeout_us<=now_us)); 134 | if(next_timeout_us>0){ 135 | RegisterAlarm(next_timeout_us,cb); 136 | } 137 | } 138 | if(has_event&&visitor_){ 139 | visitor_->PostProcessing(); 140 | } 141 | UpdateTimer(); 142 | } 143 | BaseAlarm::BaseAlarm() : engine_(NULL), registered_(false) {} 144 | 145 | BaseAlarm::~BaseAlarm() { UnregisterIfRegistered(); } 146 | 147 | int64_t BaseAlarm::OnAlarm() { 148 | registered_ = false; 149 | return 0; 150 | } 151 | 152 | void BaseAlarm::OnRegistration(const Ns3QuicAlarmEngine::AlarmRegToken& token, 153 | Ns3QuicAlarmEngine* engine) { 154 | QUICHE_DCHECK_EQ(false, registered_); 155 | 156 | token_ = token; 157 | engine_ =engine; 158 | registered_ = true; 159 | } 160 | 161 | void BaseAlarm::OnUnregistration() { registered_ = false; } 162 | 163 | void BaseAlarm::OnShutdown(Ns3QuicAlarmEngine* /*engine*/) { 164 | registered_ = false; 165 | engine_ = NULL; 166 | } 167 | 168 | // If the alarm was registered, unregister it. 169 | void BaseAlarm::UnregisterIfRegistered() { 170 | if (!registered_) { 171 | return; 172 | } 173 | 174 | engine_->UnregisterAlarm(token_); 175 | } 176 | 177 | void BaseAlarm::ReregisterAlarm(int64_t timeout_time_in_us) { 178 | QUICHE_DCHECK(registered_); 179 | token_ = engine_->ReregisterAlarm(token_, timeout_time_in_us); 180 | } 181 | class Ns3Alarm:public QuicAlarm{ 182 | public: 183 | Ns3Alarm(Ns3QuicAlarmEngine* engine,QuicArenaScopedPtr delegate) 184 | :QuicAlarm(std::move(delegate)), 185 | engine_(engine), 186 | ns3_alarm_impl_(this) { 187 | } 188 | protected: 189 | void SetImpl() override { 190 | QUICHE_DCHECK(deadline().IsInitialized()); 191 | int64_t timeout_us=(deadline() - QuicTime::Zero()).ToMicroseconds(); 192 | engine_->RegisterAlarm(timeout_us, &ns3_alarm_impl_); 193 | } 194 | 195 | void CancelImpl() override { 196 | QUICHE_DCHECK(!deadline().IsInitialized()); 197 | ns3_alarm_impl_.UnregisterIfRegistered(); 198 | } 199 | 200 | void UpdateImpl() override { 201 | QUICHE_DCHECK(deadline().IsInitialized()); 202 | int64_t timeout_us = (deadline() - QuicTime::Zero()).ToMicroseconds(); 203 | if (ns3_alarm_impl_.registered()) { 204 | ns3_alarm_impl_.ReregisterAlarm(timeout_us); 205 | } else { 206 | engine_->RegisterAlarm(timeout_us, &ns3_alarm_impl_); 207 | } 208 | } 209 | 210 | private: 211 | class Ns3AlarmImpl : public BaseAlarm{ 212 | public: 213 | 214 | explicit Ns3AlarmImpl(Ns3Alarm* alarm) : alarm_(alarm) {} 215 | void *alarm_addr() override {return alarm_;} 216 | // Use the same integer type as the base class. 217 | int64_t OnAlarm() override { 218 | BaseAlarm::OnAlarm(); 219 | alarm_->Fire(); 220 | // Fire will take care of registering the alarm, if needed. 221 | return 0; 222 | } 223 | 224 | private: 225 | Ns3Alarm* alarm_; 226 | }; 227 | 228 | Ns3QuicAlarmEngine* engine_; 229 | Ns3AlarmImpl ns3_alarm_impl_; 230 | }; 231 | Ns3AlarmFactory::Ns3AlarmFactory(Ns3QuicAlarmEngine *engine):engine_(engine){} 232 | Ns3AlarmFactory::~Ns3AlarmFactory()=default; 233 | QuicAlarm* Ns3AlarmFactory::CreateAlarm(QuicAlarm::Delegate* delegate){ 234 | return new Ns3Alarm(engine_, 235 | QuicArenaScopedPtr(delegate)); 236 | } 237 | QuicArenaScopedPtr Ns3AlarmFactory::CreateAlarm( 238 | QuicArenaScopedPtr delegate, 239 | QuicConnectionArena* arena){ 240 | if (arena != nullptr) { 241 | return arena->New(engine_, std::move(delegate)); 242 | } 243 | return QuicArenaScopedPtr( 244 | new Ns3Alarm(engine_, std::move(delegate))); 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-alarm-engine.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include "ns3/object.h" 6 | #include "ns3/event-id.h" 7 | 8 | #include "gquiche/quic/core/quic_alarm.h" 9 | #include "gquiche/quic/core/quic_alarm_factory.h" 10 | #include "gquiche/quic/core/quic_one_block_arena.h" 11 | #include "gquiche/quic/core/quic_types.h" 12 | namespace quic{ 13 | class AlarmCallbackInterface; 14 | class Ns3QuicAlarmEngine:public ns3::Object{ 15 | public: 16 | typedef AlarmCallbackInterface AlarmCB; 17 | typedef std::multimap TimeToAlarmCBMap; 18 | typedef TimeToAlarmCBMap::iterator AlarmRegToken; 19 | class Visitor{ 20 | public: 21 | virtual ~Visitor(){} 22 | virtual void PostProcessing()=0; 23 | }; 24 | 25 | Ns3QuicAlarmEngine(Perspective role=Perspective::IS_CLIENT); 26 | ~Ns3QuicAlarmEngine(); 27 | void Shutdown(); 28 | void set_visitor(Visitor *visitor){visitor_=visitor;} 29 | void RegisterAlarm(int64_t timeout_us,AlarmCB* ac); 30 | void UnregisterAlarm(const AlarmRegToken &iterator_token); 31 | AlarmRegToken ReregisterAlarm(AlarmRegToken &iterator_token, int64_t timeout_us); 32 | std::string Name(); 33 | private: 34 | struct AlarmCBHash { 35 | size_t operator()(AlarmCB* const& p) const { 36 | return reinterpret_cast(p); 37 | } 38 | }; 39 | void UpdateTimer(); 40 | void OnTimeout(); 41 | Perspective role_; 42 | using AlarmCBMap = std::unordered_set; 43 | AlarmCBMap all_alarms_; 44 | TimeToAlarmCBMap alarm_map_; 45 | Visitor *visitor_=nullptr; 46 | ns3::EventId timer_; 47 | }; 48 | class AlarmCallbackInterface{ 49 | public: 50 | virtual ~AlarmCallbackInterface(){} 51 | // Returns: 52 | // the unix time (in microseconds) at which this alarm should be signaled 53 | // again, or 0 if the alarm should be removed. 54 | virtual int64_t OnAlarm()=0; 55 | virtual void OnRegistration(const Ns3QuicAlarmEngine::AlarmRegToken &token,Ns3QuicAlarmEngine *engine)=0; 56 | virtual void OnUnregistration()=0; 57 | virtual void OnShutdown(Ns3QuicAlarmEngine *engine)=0; 58 | virtual void* alarm_addr()=0; 59 | }; 60 | class BaseAlarm:public AlarmCallbackInterface{ 61 | public: 62 | BaseAlarm(); 63 | ~BaseAlarm() override; 64 | // Marks the alarm as unregistered and returns 0. The return value may be 65 | // safely ignored by subclasses. 66 | int64_t OnAlarm() override; 67 | 68 | // Marks the alarm as registered, and stores the token. 69 | void OnRegistration(const Ns3QuicAlarmEngine::AlarmRegToken& token, 70 | Ns3QuicAlarmEngine* engine) override; 71 | 72 | // Marks the alarm as unregistered. 73 | void OnUnregistration() override; 74 | 75 | // Marks the alarm as unregistered. 76 | void OnShutdown(Ns3QuicAlarmEngine* engine) override; 77 | 78 | // If the alarm was registered, unregister it. 79 | void UnregisterIfRegistered(); 80 | 81 | // Reregisters the alarm at specified time. 82 | void ReregisterAlarm(int64_t timeout_time_in_us); 83 | 84 | bool registered() const { return registered_; } 85 | 86 | const Ns3QuicAlarmEngine* eps() const { return engine_; } 87 | 88 | private: 89 | Ns3QuicAlarmEngine::AlarmRegToken token_; 90 | Ns3QuicAlarmEngine* engine_; 91 | bool registered_; 92 | }; 93 | class Ns3AlarmFactory:public QuicAlarmFactory{ 94 | public: 95 | Ns3AlarmFactory(Ns3QuicAlarmEngine *engine); 96 | ~Ns3AlarmFactory(); 97 | // QuicAlarmFactory interface. 98 | QuicAlarm* CreateAlarm(QuicAlarm::Delegate* delegate) override; 99 | QuicArenaScopedPtr CreateAlarm( 100 | QuicArenaScopedPtr delegate, 101 | QuicConnectionArena* arena) override; 102 | private: 103 | Ns3QuicAlarmEngine *engine_=nullptr; 104 | }; 105 | } 106 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-backend.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "gquiche/quic/platform/api/quic_logging.h" 3 | 4 | #include "ns3/log.h" 5 | #include "ns3/assert.h" 6 | #include "ns3/simulator.h" 7 | #include "ns3-quic-backend.h" 8 | #include "ns3-quic-alarm-engine.h" 9 | #include "ns3-quic-session-base.h" 10 | #include "ns3-transport-stream.h" 11 | using namespace ns3; 12 | NS_LOG_COMPONENT_DEFINE("Ns3QuicBackendBase"); 13 | namespace quic{ 14 | Ns3QuicEndpointBase::Ns3QuicEndpointBase(Ns3QuicBackendBase* backend): 15 | backend_(backend){} 16 | 17 | Ns3QuicBackendBase::Ns3QuicBackendBase(Ns3QuicAlarmEngine* engine): 18 | engine_(engine){} 19 | 20 | HelloClientEndpoint::HelloClientEndpoint(Ns3QuicBackendBase* backend,bool bidi_channel): 21 | Ns3QuicEndpointBase(backend), 22 | bidi_channel_(bidi_channel){} 23 | HelloClientEndpoint::~HelloClientEndpoint(){ 24 | ns3::Time now=ns3::Simulator::Now(); 25 | if(channel_){ 26 | channel_->set_notifier(nullptr); 27 | channel_=nullptr; 28 | } 29 | NS_LOG_INFO("HelloClientEndpoint::dtor "< channel_ptr; 43 | if(bidi_channel_){ 44 | stream=session_->OpenOutgoingBidirectionalStream(); 45 | channel_=new HelloBidiChannel(stream); 46 | channel_ptr.reset(channel_); 47 | channel_ptr->set_notifier(this); 48 | stream->set_visitor(std::move(channel_ptr)); 49 | ((HelloBidiChannel*)(channel_))->SendHello(); 50 | }else{ 51 | stream=session_->OpenOutgoingUnidirectionalStream(); 52 | channel_=new HelloUnidiWriteChannel(stream); 53 | channel_ptr.reset(channel_); 54 | channel_ptr->set_notifier(this); 55 | stream->set_visitor(std::move(channel_ptr)); 56 | ((HelloUnidiWriteChannel*)(channel_))->SendHello(); 57 | } 58 | } 59 | void HelloClientEndpoint::OnSessionDestroy(Ns3QuicSessionBase *session){ 60 | ns3::Time now=ns3::Simulator::Now(); 61 | NS_LOG_INFO("HelloClientEndpoint::OnSessionDestroy "<set_notifier(nullptr); 76 | channel_=nullptr; 77 | } 78 | NS_LOG_INFO("EchoServerEndpoint::dtor "< channel_ptr; 84 | channel_ptr.reset(channel_); 85 | channel_ptr->set_notifier(this); 86 | stream->set_visitor(std::move(channel_ptr)); 87 | } 88 | void EchoServerEndpoint::OnIncomingUnidirectionalStream(Ns3TransportStream *stream){ 89 | channel_=new HelloUnidiReadChannel(stream); 90 | std::unique_ptr channel_ptr; 91 | channel_ptr.reset(channel_); 92 | channel_ptr->set_notifier(this); 93 | stream->set_visitor(std::move(channel_ptr)); 94 | } 95 | void EchoServerEndpoint::OnSessionReady(Ns3QuicSessionBase *session){ 96 | ready_=true; 97 | session_=session; 98 | } 99 | void EchoServerEndpoint::OnSessionDestroy(Ns3QuicSessionBase *session){ 100 | ns3::Time now=ns3::Simulator::Now(); 101 | NS_LOG_INFO("EchoServerEndpoint::OnSessionDestroy "<set_notifier(nullptr); 133 | channel_=nullptr; 134 | } 135 | NS_LOG_INFO("BandwidthClientEndpoint::dtor "< channel_ptr; 148 | stream=session_->OpenOutgoingUnidirectionalStream(); 149 | channel_=new BandwidthWriteChannel(stream,backend_->get_engine()); 150 | channel_ptr.reset(channel_); 151 | channel_ptr->set_notifier(this); 152 | stream->set_visitor(std::move(channel_ptr)); 153 | ((BandwidthWriteChannel*)(channel_))->StartFillData(); 154 | 155 | } 156 | void BandwidthClientEndpoint::OnSessionDestroy(Ns3QuicSessionBase *session){ 157 | ns3::Time now=ns3::Simulator::Now(); 158 | NS_LOG_INFO("BandwidthClientEndpoint::OnSessionDestroy "<set_notifier(nullptr); 173 | channel_=nullptr; 174 | } 175 | NS_LOG_INFO("BandwidthServerEndpoint::dtor "< channel_ptr; 184 | channel_ptr.reset(channel_); 185 | channel_ptr->set_notifier(this); 186 | stream->set_visitor(std::move(channel_ptr)); 187 | } 188 | void BandwidthServerEndpoint::OnSessionReady(Ns3QuicSessionBase *session){ 189 | ready_=true; 190 | session_=session; 191 | } 192 | void BandwidthServerEndpoint::OnSessionDestroy(Ns3QuicSessionBase *session){ 193 | ns3::Time now=ns3::Simulator::Now(); 194 | NS_LOG_INFO("BandwidthServerEndpoint::OnSessionDestroy "< 3 | #include "ns3/ns3-quic-public.h" 4 | #include "ns3-quic-channel.h" 5 | namespace quic{ 6 | class Ns3TransportStream; 7 | class Ns3QuicSessionBase; 8 | class Ns3QuicAlarmEngine; 9 | class Ns3QuicBackendBase; 10 | class Ns3QuicEndpointBase{ 11 | public: 12 | Ns3QuicEndpointBase(Ns3QuicBackendBase* backend); 13 | virtual ~Ns3QuicEndpointBase(){} 14 | virtual void OnIncomingBidirectionalStream(Ns3TransportStream *stream)=0; 15 | virtual void OnIncomingUnidirectionalStream(Ns3TransportStream *stream)=0; 16 | virtual void OnSessionReady(Ns3QuicSessionBase *session)=0; 17 | virtual void OnSessionDestroy(Ns3QuicSessionBase *session)=0; 18 | protected: 19 | Ns3QuicBackendBase *backend_=nullptr; 20 | Ns3QuicSessionBase *session_=nullptr; 21 | bool ready_=false; 22 | }; 23 | class Ns3QuicBackendBase{ 24 | public: 25 | Ns3QuicBackendBase(Ns3QuicAlarmEngine* engine); 26 | virtual ~Ns3QuicBackendBase(){} 27 | virtual Ns3QuicEndpointBase* CreateEndpoint(Ns3QuicSessionBase *session)=0; 28 | Ns3QuicAlarmEngine* get_engine() {return engine_;} 29 | protected: 30 | Ns3QuicAlarmEngine *engine_=nullptr; 31 | }; 32 | 33 | class HelloClientEndpoint:public Ns3QuicEndpointBase, 34 | public Ns3QuicChannelBase::Notifier{ 35 | public: 36 | HelloClientEndpoint(Ns3QuicBackendBase* backend,bool bidi_channel); 37 | ~HelloClientEndpoint() override; 38 | //from Ns3QuicEndpointBase 39 | void OnIncomingBidirectionalStream(Ns3TransportStream *stream) override; 40 | void OnIncomingUnidirectionalStream(Ns3TransportStream *stream) override; 41 | void OnSessionReady(Ns3QuicSessionBase *session) override; 42 | void OnSessionDestroy(Ns3QuicSessionBase *session) override; 43 | //from Ns3QuicChannelBase::Notifier 44 | void OnChannelDestroy(Ns3QuicChannelBase *channel) override; 45 | private: 46 | Ns3QuicChannelBase *channel_=nullptr; 47 | bool bidi_channel_=false; 48 | }; 49 | class EchoServerEndpoint:public Ns3QuicEndpointBase, 50 | public Ns3QuicChannelBase::Notifier{ 51 | public: 52 | EchoServerEndpoint(Ns3QuicBackendBase* backend); 53 | ~EchoServerEndpoint() override; 54 | //from Ns3QuicEndpointBase 55 | void OnIncomingBidirectionalStream(Ns3TransportStream *stream) override; 56 | void OnIncomingUnidirectionalStream(Ns3TransportStream *stream) override; 57 | void OnSessionReady(Ns3QuicSessionBase *session) override; 58 | void OnSessionDestroy(Ns3QuicSessionBase *session) override; 59 | //from Ns3QuicChannelBase::Notifier 60 | void OnChannelDestroy(Ns3QuicChannelBase *channel) override; 61 | private: 62 | Ns3QuicChannelBase *channel_=nullptr; 63 | }; 64 | 65 | class HelloClientBackend:public Ns3QuicBackendBase{ 66 | public: 67 | HelloClientBackend(Ns3QuicAlarmEngine* engine,bool bidi_channel=true); 68 | ~HelloClientBackend() override{} 69 | Ns3QuicEndpointBase* CreateEndpoint(Ns3QuicSessionBase *session) override; 70 | private: 71 | bool bidi_channel_=true; 72 | }; 73 | class HelloServerBackend:public Ns3QuicBackendBase{ 74 | public: 75 | HelloServerBackend(Ns3QuicAlarmEngine* engine); 76 | ~HelloServerBackend() override {} 77 | Ns3QuicEndpointBase* CreateEndpoint(Ns3QuicSessionBase *session) override; 78 | }; 79 | 80 | class BandwidthClientEndpoint:public Ns3QuicEndpointBase, 81 | public Ns3QuicChannelBase::Notifier{ 82 | public: 83 | BandwidthClientEndpoint(Ns3QuicBackendBase* backend); 84 | ~BandwidthClientEndpoint() override; 85 | //from Ns3QuicEndpointBase 86 | void OnIncomingBidirectionalStream(Ns3TransportStream *stream) override; 87 | void OnIncomingUnidirectionalStream(Ns3TransportStream *stream) override; 88 | void OnSessionReady(Ns3QuicSessionBase *session) override; 89 | void OnSessionDestroy(Ns3QuicSessionBase *session) override; 90 | //from Ns3QuicChannelBase::Notifier 91 | void OnChannelDestroy(Ns3QuicChannelBase *channel) override; 92 | private: 93 | Ns3QuicChannelBase *channel_=nullptr; 94 | }; 95 | 96 | class BandwidthServerEndpoint:public Ns3QuicEndpointBase, 97 | public Ns3QuicChannelBase::Notifier{ 98 | public: 99 | BandwidthServerEndpoint(Ns3QuicBackendBase* backend); 100 | ~BandwidthServerEndpoint() override; 101 | //from Ns3QuicEndpointBase 102 | void OnIncomingBidirectionalStream(Ns3TransportStream *stream) override; 103 | void OnIncomingUnidirectionalStream(Ns3TransportStream *stream) override; 104 | void OnSessionReady(Ns3QuicSessionBase *session) override; 105 | void OnSessionDestroy(Ns3QuicSessionBase *session) override; 106 | //from Ns3QuicChannelBase::Notifier 107 | void OnChannelDestroy(Ns3QuicChannelBase *channel) override; 108 | private: 109 | Ns3QuicChannelBase *channel_=nullptr; 110 | }; 111 | 112 | class BandwidthClientBackend:public Ns3QuicBackendBase{ 113 | public: 114 | BandwidthClientBackend(Ns3QuicAlarmEngine* engine); 115 | ~BandwidthClientBackend() override {} 116 | Ns3QuicEndpointBase* CreateEndpoint(Ns3QuicSessionBase *session) override; 117 | }; 118 | 119 | class BandwidthServerBackend:public Ns3QuicBackendBase{ 120 | public: 121 | BandwidthServerBackend(Ns3QuicAlarmEngine* engine); 122 | ~BandwidthServerBackend() override {} 123 | Ns3QuicEndpointBase* CreateEndpoint(Ns3QuicSessionBase *session) override; 124 | }; 125 | } 126 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-channel.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "gquiche/quic/platform/api/quic_logging.h" 4 | 5 | #include "ns3/log.h" 6 | #include "ns3/simulator.h" 7 | #include "ns3-quic-channel.h" 8 | #include "ns3-quic-alarm-engine.h" 9 | #include "ns3-quic-clock.h" 10 | NS_LOG_COMPONENT_DEFINE("Ns3QuicChannelBase"); 11 | namespace quic{ 12 | namespace{ 13 | const char *hello="hello world"; 14 | char kContent[1500]={0}; 15 | int kWritePackets=6; 16 | QuicTime::Delta kWriteDelta=QuicTime::Delta::FromMilliseconds(50); 17 | } 18 | void ContentInit(const char v){ 19 | int len=sizeof(kContent)/sizeof(char); 20 | for(int i=0;iWrite(hello,strlen(hello),true); 33 | } 34 | void HelloBidiChannel::OnCanRead(){ 35 | std::string buffer; 36 | bool fin=false; 37 | stream_->Read(&buffer,fin); 38 | NS_LOG_INFO("HelloBidiChannel::read "<OnChannelDestroy(this); 45 | } 46 | } 47 | 48 | EchoBidiChannel::EchoBidiChannel(Ns3TransportStream *stream): 49 | stream_(stream){} 50 | 51 | void EchoBidiChannel::OnCanRead(){ 52 | std::string buffer; 53 | bool fin=false; 54 | stream_->Read(&buffer,fin); 55 | stream_->Write(buffer.data(),buffer.size(),true); 56 | NS_LOG_INFO("EchoBidiChannel::read "<OnChannelDestroy(this); 63 | } 64 | } 65 | 66 | HelloUnidiWriteChannel::HelloUnidiWriteChannel(Ns3TransportStream *stream): 67 | stream_(stream){} 68 | 69 | void HelloUnidiWriteChannel::SendHello(){ 70 | stream_->Write(hello,strlen(hello),true); 71 | } 72 | void HelloUnidiWriteChannel::OnCanRead(){} 73 | void HelloUnidiWriteChannel::OnCanWrite(){ 74 | NS_LOG_INFO("HelloUnidiWriteChannel::OnCanWrite"); 75 | } 76 | void HelloUnidiWriteChannel::OnDestroy(){ 77 | NS_LOG_INFO("HelloUnidiWriteChannel::OnDestroy"); 78 | if(notifier_){ 79 | notifier_->OnChannelDestroy(this); 80 | } 81 | } 82 | 83 | HelloUnidiReadChannel::HelloUnidiReadChannel(Ns3TransportStream *stream): 84 | stream_(stream){} 85 | 86 | void HelloUnidiReadChannel::OnCanRead(){ 87 | std::string buffer; 88 | bool fin=false; 89 | stream_->Read(&buffer,fin); 90 | NS_LOG_INFO("HelloUnidiReadChannel::read "<OnChannelDestroy(this); 97 | } 98 | } 99 | 100 | class WriteDelegate:public QuicAlarm::Delegate{ 101 | public: 102 | WriteDelegate(BandwidthWriteChannel *entity):entity_(entity){} 103 | ~WriteDelegate() override{} 104 | //from QuicAlarm::Delegate 105 | void OnAlarm() override{ 106 | entity_->OnTimeout(); 107 | } 108 | private: 109 | BandwidthWriteChannel *entity_; 110 | }; 111 | BandwidthWriteChannel::BandwidthWriteChannel(Ns3TransportStream *stream,Ns3QuicAlarmEngine *engine): 112 | stream_(stream){ 113 | alarm_factory_.reset(new Ns3AlarmFactory(engine)); 114 | alarm_.reset(alarm_factory_->CreateAlarm(new WriteDelegate(this))); 115 | } 116 | BandwidthWriteChannel::~BandwidthWriteChannel(){ 117 | if(alarm_&&alarm_->IsSet()){ 118 | alarm_->Cancel(); 119 | } 120 | alarm_=nullptr; 121 | alarm_factory_=nullptr; 122 | NS_LOG_INFO("BandwidthWriteChannel::dtor "<IsSet()){ 132 | alarm_->Cancel(); 133 | } 134 | if(notifier_){ 135 | notifier_->OnChannelDestroy(this); 136 | } 137 | } 138 | 139 | void BandwidthWriteChannel::OnTimeout(){ 140 | QuicTime now=Ns3QuicClock::Instance()->Now(); 141 | WriteData(); 142 | alarm_->Update(now+kWriteDelta,kAlarmGranularity); 143 | } 144 | void BandwidthWriteChannel::StartFillData(){ 145 | WriteData(); 146 | QuicTime now=Ns3QuicClock::Instance()->Now(); 147 | alarm_->Set(now+kWriteDelta); 148 | } 149 | void BandwidthWriteChannel::WriteData(){ 150 | int couter=0; 151 | QuicTime now=Ns3QuicClock::Instance()->Now(); 152 | if(stream_){ 153 | for(int i=0;iWrite(kContent,1500,false); 155 | if(!success){ 156 | break; 157 | } 158 | couter++; 159 | write_bytes_+=1500; 160 | } 161 | } 162 | float seconds=(now-QuicTime::Zero()).ToMilliseconds()*1.0/1000; 163 | NS_LOG_INFO(seconds<<" BandwidthWriteChannel::WriteData "<Read(&buffer,fin); 175 | read_bytes_+=buffer.size(); 176 | } 177 | void BandwidthReadChannel::OnCanWrite(){} 178 | void BandwidthReadChannel::OnDestroy(){ 179 | NS_LOG_INFO("BandwidthReadChannel::OnDestroy"); 180 | if(notifier_){ 181 | notifier_->OnChannelDestroy(this); 182 | } 183 | } 184 | 185 | } 186 | 187 | 188 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-channel.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "gquiche/quic/core/quic_alarm.h" 4 | #include "gquiche/quic/core/quic_alarm_factory.h" 5 | #include "ns3-transport-stream.h" 6 | #include "ns3/ns3-quic-public.h" 7 | namespace quic{ 8 | class Ns3QuicAlarmEngine; 9 | class Ns3QuicChannelBase:public Ns3TransportStream::Visitor{ 10 | public: 11 | class Notifier{ 12 | public: 13 | virtual ~Notifier(){} 14 | virtual void OnChannelDestroy(Ns3QuicChannelBase *channel)=0; 15 | }; 16 | void set_notifier(Notifier *notifier); 17 | virtual ~Ns3QuicChannelBase(){} 18 | protected: 19 | Notifier *notifier_=nullptr; 20 | }; 21 | class HelloBidiChannel:public Ns3QuicChannelBase{ 22 | public: 23 | HelloBidiChannel(Ns3TransportStream *stream); 24 | ~HelloBidiChannel() override{} 25 | void SendHello(); 26 | //from Ns3TransportStream::Visitor 27 | void OnCanRead() override; 28 | void OnCanWrite() override; 29 | void OnDestroy() override; 30 | private: 31 | Ns3TransportStream *stream_=nullptr; 32 | 33 | }; 34 | class EchoBidiChannel:public Ns3QuicChannelBase{ 35 | public: 36 | EchoBidiChannel(Ns3TransportStream *stream); 37 | ~EchoBidiChannel() override{} 38 | //from Ns3TransportStream::Visitor 39 | void OnCanRead() override; 40 | void OnCanWrite() override; 41 | void OnDestroy() override; 42 | private: 43 | Ns3TransportStream *stream_=nullptr; 44 | }; 45 | class HelloUnidiWriteChannel:public Ns3QuicChannelBase{ 46 | public: 47 | HelloUnidiWriteChannel(Ns3TransportStream *stream); 48 | ~HelloUnidiWriteChannel() override{} 49 | void SendHello(); 50 | //from Ns3TransportStream::Visitor 51 | void OnCanRead() override; 52 | void OnCanWrite() override; 53 | void OnDestroy() override; 54 | private: 55 | Ns3TransportStream *stream_=nullptr; 56 | }; 57 | class HelloUnidiReadChannel:public Ns3QuicChannelBase{ 58 | public: 59 | HelloUnidiReadChannel(Ns3TransportStream *stream); 60 | ~HelloUnidiReadChannel() override{} 61 | //from Ns3TransportStream::Visitor 62 | void OnCanRead() override; 63 | void OnCanWrite() override; 64 | void OnDestroy() override; 65 | private: 66 | Ns3TransportStream *stream_=nullptr; 67 | }; 68 | 69 | class BandwidthWriteChannel:public Ns3QuicChannelBase{ 70 | public: 71 | BandwidthWriteChannel(Ns3TransportStream *stream,Ns3QuicAlarmEngine *engine); 72 | ~BandwidthWriteChannel() override; 73 | //from Ns3TransportStream::Visitor 74 | void OnCanRead() override; 75 | void OnCanWrite() override; 76 | void OnDestroy() override; 77 | void OnTimeout(); 78 | void StartFillData(); 79 | private: 80 | void WriteData(); 81 | std::unique_ptr alarm_factory_; 82 | std::unique_ptr alarm_; 83 | Ns3TransportStream *stream_=nullptr; 84 | uint32_t write_bytes_=0; 85 | }; 86 | class BandwidthReadChannel:public Ns3QuicChannelBase{ 87 | public: 88 | BandwidthReadChannel(Ns3TransportStream *stream); 89 | ~BandwidthReadChannel() override; 90 | //from Ns3TransportStream::Visitor 91 | void OnCanRead() override; 92 | void OnCanWrite() override; 93 | void OnDestroy() override; 94 | private: 95 | Ns3TransportStream *stream_=nullptr; 96 | uint32_t read_bytes_=0; 97 | }; 98 | 99 | } 100 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-client-app.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "ns3/event-id.h" 5 | #include "ns3/callback.h" 6 | #include "ns3/application.h" 7 | #include "ns3/socket.h" 8 | #include "ns3/network-module.h" 9 | #include "ns3/internet-module.h" 10 | #include "ns3/ns3-quic-public.h" 11 | namespace ns3{ 12 | class QuicClientAppImpl; 13 | class QuicClientApp:public Application{ 14 | public: 15 | QuicClientApp(quic::BackendType backend_type,const char *cc_name); 16 | ~QuicClientApp() override; 17 | void Bind(uint16_t port=0); 18 | void set_peer(const Ipv4Address& ip_addr,uint16_t port); 19 | InetSocketAddress GetLocalAddress() const; 20 | void RecvPacket(Ptr socket); 21 | void SendToNetwork(const char *buffer,size_t sz); 22 | 23 | typedef Callback TraceOneFloatValue; 24 | typedef Callback TraceOneIntValue; 25 | void SetRateTraceFuc(TraceOneFloatValue cb); 26 | void SetCwndTraceFun(TraceOneIntValue cb); 27 | void SetInFlightTraceFun(TraceOneIntValue cb); 28 | 29 | private: 30 | virtual void StartApplication() override; 31 | virtual void StopApplication() override; 32 | Ptr m_socket; 33 | Ipv4Address m_bindIp; 34 | uint16_t m_bindPort=0; 35 | Ipv4Address m_peerIp; 36 | uint16_t m_peerPort; 37 | bool m_running=false; 38 | uint64_t m_seq=1; 39 | std::unique_ptr m_impl; 40 | TraceOneFloatValue m_traceRate; 41 | TraceOneIntValue m_traceCwnd; 42 | TraceOneIntValue m_traceInFlight; 43 | int64_t m_rate=0; 44 | int m_cwnd=0; 45 | int m_inFlight=0; 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-client-session.cc: -------------------------------------------------------------------------------- 1 | #include "gquiche/quic/platform/api/quic_logging.h" 2 | #include "ns3-quic-client-session.h" 3 | #include "ns3-transport-stream.h" 4 | #include "ns3-quic-backend.h" 5 | namespace quic{ 6 | Ns3QuicClientSession::Ns3QuicClientSession(std::unique_ptr connection_ptr, 7 | Visitor* owner, 8 | const QuicConfig& config, 9 | const ParsedQuicVersionVector& supported_versions, 10 | const QuicServerId& server_id, 11 | QuicCryptoClientConfig* crypto_config, 12 | Ns3QuicBackendBase *backend) 13 | :Ns3QuicSessionBase(connection_ptr.get(),owner,config,supported_versions,0), 14 | backend_(backend), 15 | connection_own_(std::move(connection_ptr)){ 16 | /*for (const ParsedQuicVersion& version : supported_versions) { 17 | QUIC_BUG_IF(Ns3QuicClientSession,version.handshake_protocol != PROTOCOL_TLS1_3) 18 | << "QuicTransport requires TLS 1.3 handshake"; 19 | }*/ 20 | //std::cout<<"max uni: "<( 23 | server_id, this,crypto_config->proof_verifier()->CreateDefaultContext(), 24 | crypto_config,/*proof_handler=*/this, /*has_application_state = */ true); 25 | endpoint_.reset(backend_->CreateEndpoint(this)); 26 | if(!endpoint_){ 27 | QUIC_LOG(ERROR)<<"endpoint is null "<CloseConnection(QUIC_INTERNAL_ERROR, "Create Endpoint Failed", 29 | ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); 30 | } 31 | } 32 | Ns3QuicClientSession::~Ns3QuicClientSession(){ 33 | if(endpoint_){ 34 | endpoint_->OnSessionDestroy(this); 35 | } 36 | } 37 | Ns3TransportStream* Ns3QuicClientSession::OpenOutgoingBidirectionalStream(){ 38 | if (!CanOpenNextOutgoingBidirectionalStream()) { 39 | QUIC_BUG(Ns3QuicClientSession)<< "Attempted to open a stream in violation of flow control"; 40 | return nullptr; 41 | } 42 | return CreateStream(GetNextOutgoingBidirectionalStreamId()); 43 | } 44 | Ns3TransportStream* Ns3QuicClientSession::OpenOutgoingUnidirectionalStream(){ 45 | if (!CanOpenNextOutgoingUnidirectionalStream()) { 46 | QUIC_BUG(Ns3QuicClientSession)<< "Attempted to open a stream in violation of flow control"; 47 | return nullptr; 48 | } 49 | return CreateStream(GetNextOutgoingUnidirectionalStreamId()); 50 | } 51 | void Ns3QuicClientSession::Initialize(){ 52 | QuicSession::Initialize(); 53 | CryptoConnect(); 54 | } 55 | void Ns3QuicClientSession::OnAlpnSelected(absl::string_view alpn) { 56 | // Defense in-depth: ensure the ALPN selected is the desired one. 57 | if (alpn != QuicTransportAlpn()) { 58 | QUIC_BUG(Ns3QuicClientSession)<< "QuicTransport negotiated non-QuicTransport ALPN: " << alpn; 59 | connection()->CloseConnection( 60 | QUIC_INTERNAL_ERROR, "QuicTransport negotiated non-QuicTransport ALPN", 61 | ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); 62 | return; 63 | } 64 | alpn_received_ = true; 65 | } 66 | QuicStream* Ns3QuicClientSession::CreateIncomingStream(QuicStreamId id){ 67 | QUIC_DVLOG(1) << "Creating incoming QuicTransport stream " << id; 68 | Ns3TransportStream* stream = CreateStream(id); 69 | if(BIDIRECTIONAL==stream->type()){ 70 | endpoint_->OnIncomingBidirectionalStream(stream); 71 | }else{ 72 | endpoint_->OnIncomingUnidirectionalStream(stream); 73 | } 74 | return stream; 75 | } 76 | QuicStream* Ns3QuicClientSession::CreateIncomingStream(PendingStream* /*pending*/){ 77 | return nullptr; 78 | } 79 | void Ns3QuicClientSession::SetDefaultEncryptionLevel(EncryptionLevel level){ 80 | if(ENCRYPTION_FORWARD_SECURE==level){ 81 | ready_=true; 82 | endpoint_->OnSessionReady(this); 83 | } 84 | } 85 | void Ns3QuicClientSession::OnTlsHandshakeComplete(){ 86 | QuicSession::OnTlsHandshakeComplete(); 87 | ready_=true; 88 | endpoint_->OnSessionReady(this); 89 | } 90 | void Ns3QuicClientSession::OnMessageReceived(absl::string_view message){ 91 | //done nothing 92 | } 93 | void Ns3QuicClientSession::OnProofValid(const QuicCryptoClientConfig::CachedState& cached){ 94 | 95 | } 96 | void Ns3QuicClientSession::OnProofVerifyDetailsAvailable(const ProofVerifyDetails& verify_details){ 97 | 98 | } 99 | 100 | int Ns3QuicClientSession::GetNumSentClientHellos() const{ 101 | return crypto_stream_->num_sent_client_hellos(); 102 | } 103 | bool Ns3QuicClientSession::EarlyDataAccepted() const{ 104 | return crypto_stream_->EarlyDataAccepted(); 105 | } 106 | bool Ns3QuicClientSession::ReceivedInchoateReject() const{ 107 | return crypto_stream_->ReceivedInchoateReject(); 108 | } 109 | int Ns3QuicClientSession::GetNumReceivedServerConfigUpdates() const{ 110 | return crypto_stream_->num_scup_messages_received(); 111 | } 112 | bool Ns3QuicClientSession::HasActiveRequestStreams() const{ 113 | return GetNumActiveStreams() + num_draining_streams() > 0; 114 | } 115 | Ns3TransportStream* Ns3QuicClientSession::CreateStream(QuicStreamId id){ 116 | auto stream = std::make_unique(id, this); 117 | Ns3TransportStream* stream_ptr = stream.get(); 118 | ActivateStream(std::move(stream)); 119 | return stream_ptr; 120 | } 121 | void Ns3QuicClientSession::CloseSession(){ 122 | if(connection()&&connection()->connected()){ 123 | connection()->CloseConnection( 124 | QUIC_PEER_GOING_AWAY,"Session disconnecting", 125 | ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); 126 | } 127 | } 128 | void Ns3QuicClientSession::OnCanCreateNewOutgoingStream(bool unidirectional){ 129 | 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-client-session.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "absl/strings/string_view.h" 6 | #include "gquiche/quic/core/crypto/quic_crypto_client_config.h" 7 | #include "gquiche/quic/core/quic_config.h" 8 | #include "gquiche/quic/core/quic_connection.h" 9 | #include "gquiche/quic/core/quic_crypto_client_stream.h" 10 | #include "gquiche/quic/core/quic_crypto_stream.h" 11 | #include "gquiche/quic/core/quic_server_id.h" 12 | #include "gquiche/quic/core/quic_session.h" 13 | #include "gquiche/quic/core/quic_stream.h" 14 | #include "gquiche/quic/core/quic_versions.h" 15 | #include "gquiche/quic/platform/api/quic_bug_tracker.h" 16 | #include "gquiche/quic/platform/api/quic_containers.h" 17 | #include "gquiche/quic/quic_transport/quic_transport_protocol.h" 18 | 19 | #include "ns3-quic-session-base.h" 20 | namespace quic{ 21 | class Ns3QuicBackendBase; 22 | class Ns3QuicEndpointBase; 23 | class Ns3QuicClientSession:public Ns3QuicSessionBase, 24 | public QuicCryptoClientStream::ProofHandler{ 25 | public: 26 | Ns3QuicClientSession(std::unique_ptr connection_ptr, 27 | Visitor* owner, 28 | const QuicConfig& config, 29 | const ParsedQuicVersionVector& supported_versions, 30 | const QuicServerId& server_id, 31 | QuicCryptoClientConfig* crypto_config, 32 | Ns3QuicBackendBase *backend); 33 | ~Ns3QuicClientSession() override; 34 | //from Ns3QuicSessionBase 35 | Ns3TransportStream* OpenOutgoingBidirectionalStream() override; 36 | Ns3TransportStream* OpenOutgoingUnidirectionalStream() override; 37 | 38 | void Initialize() override; 39 | std::vector GetAlpnsToOffer() const override { 40 | return std::vector({QuicTransportAlpn()}); 41 | } 42 | void OnAlpnSelected(absl::string_view alpn) override; 43 | bool alpn_received() const { return alpn_received_; } 44 | 45 | void CryptoConnect() { crypto_stream_->CryptoConnect(); } 46 | 47 | bool ShouldKeepConnectionAlive() const override { return true; } 48 | 49 | QuicCryptoStream* GetMutableCryptoStream() override { 50 | return crypto_stream_.get(); 51 | } 52 | const QuicCryptoStream* GetCryptoStream() const override { 53 | return crypto_stream_.get(); 54 | } 55 | QuicStream* CreateIncomingStream(QuicStreamId id) override; 56 | QuicStream* CreateIncomingStream(PendingStream* /*pending*/) override; 57 | void SetDefaultEncryptionLevel(EncryptionLevel level) override; 58 | void OnTlsHandshakeComplete() override; 59 | void OnMessageReceived(absl::string_view message) override; 60 | 61 | // QuicCryptoClientStream::ProofHandler implementation. 62 | void OnProofValid(const QuicCryptoClientConfig::CachedState& cached) override; 63 | void OnProofVerifyDetailsAvailable(const ProofVerifyDetails& verify_details) override; 64 | bool IsSessionReady() const{return ready_;} 65 | // Returns the number of client hello messages that have been sent on the 66 | // crypto stream. If the handshake has completed then this is one greater 67 | // than the number of round-trips needed for the handshake. 68 | int GetNumSentClientHellos() const; 69 | // Returns true if early data (0-RTT data) was sent and the server accepted 70 | // it. 71 | bool EarlyDataAccepted() const; 72 | 73 | // Returns true if the handshake was delayed one round trip by the server 74 | // because the server wanted proof the client controls its source address 75 | // before progressing further. In Google QUIC, this would be due to an 76 | // inchoate REJ in the QUIC Crypto handshake; in IETF QUIC this would be due 77 | // to a Retry packet. 78 | // TODO(nharper): Consider a better name for this method. 79 | bool ReceivedInchoateReject() const; 80 | 81 | int GetNumReceivedServerConfigUpdates() const; 82 | // Returns true if the session has active request streams. 83 | bool HasActiveRequestStreams() const; 84 | protected: 85 | Ns3TransportStream* CreateStream(QuicStreamId id); 86 | void CloseSession(); 87 | void OnCanCreateNewOutgoingStream(bool unidirectional) override; 88 | std::unique_ptr crypto_stream_; 89 | Ns3QuicBackendBase *backend_; 90 | std::unique_ptr endpoint_; 91 | bool alpn_received_ = false; 92 | bool ready_=false; 93 | std::unique_ptr connection_own_; 94 | }; 95 | } 96 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-client.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "gquiche/quic/core/quic_constants.h" 3 | #include "gquiche/quic/core/quic_config.h" 4 | #include "url/gurl.h" 5 | 6 | #include "ns3-quic-client.h" 7 | #include "ns3-quic-backend.h" 8 | #include "ns3-quic-alarm-engine.h" 9 | #include "ns3-client-network-helper.h" 10 | #include "ns3-quic-connection-helper.h" 11 | #include "ns3-quic-client-session.h" 12 | namespace quic{ 13 | static std::string CongestionControlTypeToString(CongestionControlType cc_type) { 14 | switch (cc_type) { 15 | case kCubicBytes: 16 | return "CUBIC_BYTES"; 17 | case kRenoBytes: 18 | return "RENO_BYTES"; 19 | case kBBR: 20 | return "BBR"; 21 | case kPCC: 22 | return "CUBIC_BYTES"; 23 | case kGoogCC: 24 | return "BBR"; 25 | case kBBRv2: 26 | return "BBRv2"; 27 | default: 28 | return "???"; 29 | } 30 | } 31 | Ns3QuicClient::Ns3QuicClient(QuicSession::Visitor *owner, 32 | QuicSocketAddress server_address, 33 | const QuicServerId& server_id, 34 | const ParsedQuicVersionVector& supported_versions, 35 | std::unique_ptr proof_verifier, 36 | Ns3QuicAlarmEngine *engine, 37 | Ns3QuicBackendBase *backend, 38 | Ns3QuicPollServer *poller, 39 | CongestionControlType cc_type): 40 | Ns3QuicClient(owner,server_address,server_id,supported_versions,QuicConfig(), 41 | std::move(proof_verifier),nullptr, 42 | engine,backend,poller,cc_type){} 43 | 44 | Ns3QuicClient::Ns3QuicClient(QuicSession::Visitor *owner, 45 | QuicSocketAddress server_address, 46 | const QuicServerId& server_id, 47 | const ParsedQuicVersionVector& supported_versions, 48 | const QuicConfig& config, 49 | std::unique_ptr proof_verifier, 50 | std::unique_ptr session_cache, 51 | Ns3QuicAlarmEngine *engine, 52 | Ns3QuicBackendBase *backend, 53 | Ns3QuicPollServer *poller, 54 | CongestionControlType cc_type): 55 | QuicClientBase(server_id,supported_versions,config, 56 | new Ns3QuicConnectionHelper(QuicAllocatorType::SIMPLE), 57 | new Ns3AlarmFactory(engine), 58 | std::make_unique(poller,this), 59 | std::move(proof_verifier), 60 | std::move(session_cache)), 61 | backend_(backend), 62 | owner_(owner), 63 | cc_type_(cc_type){ 64 | set_server_address(server_address); 65 | } 66 | 67 | Ns3QuicClient::~Ns3QuicClient()=default; 68 | void Ns3QuicClient::AsynConnect(){ 69 | if(!connected()){ 70 | StartConnect(); 71 | } 72 | } 73 | Ns3QuicClientSession* Ns3QuicClient::client_session(){ 74 | return static_cast(QuicClientBase::session()); 75 | } 76 | bool Ns3QuicClient::GetBandwidth(QuicBandwidth &bandwidth) const{ 77 | bool valid=false; 78 | const QuicSession *session=QuicClientBase::session(); 79 | if(session&&session->connection()){ 80 | const QuicSentPacketManager& manager=session->connection()->sent_packet_manager(); 81 | bandwidth=manager.BandwidthEstimate(); 82 | valid=true; 83 | } 84 | return valid; 85 | } 86 | bool Ns3QuicClient::GetCongestionWindowBytes(QuicByteCount &bytes) const{ 87 | bool valid=false; 88 | const QuicSession *session=QuicClientBase::session(); 89 | if(session&&session->connection()){ 90 | const QuicSentPacketManager& manager=session->connection()->sent_packet_manager(); 91 | bytes=manager.GetCongestionWindowInBytes(); 92 | valid=true; 93 | } 94 | return valid; 95 | } 96 | bool Ns3QuicClient::GetCongestionWindowPackets(int &packets) const{ 97 | bool valid=false; 98 | const QuicSession *session=QuicClientBase::session(); 99 | if(session&&session->connection()){ 100 | const QuicSentPacketManager& manager=session->connection()->sent_packet_manager(); 101 | packets=manager.GetCongestionWindowInTcpMss(); 102 | valid=true; 103 | } 104 | return valid; 105 | } 106 | bool Ns3QuicClient::GetInFlightBytes(QuicByteCount& bytes) const{ 107 | bool valid=false; 108 | const QuicSession *session=QuicClientBase::session(); 109 | if(session&&session->connection()){ 110 | const QuicSentPacketManager& manager=session->connection()->sent_packet_manager(); 111 | bytes=manager.GetBytesInFlight(); 112 | valid=true; 113 | } 114 | return valid; 115 | } 116 | bool Ns3QuicClient::GetInFlightPackets(int& packets) const{ 117 | QuicByteCount bytes=0; 118 | bool valid=false; 119 | valid=GetInFlightBytes(bytes); 120 | if(valid){ 121 | packets=(bytes+kDefaultTCPMSS-1)/kDefaultTCPMSS; 122 | } 123 | return valid; 124 | } 125 | std::string Ns3QuicClient::GetCongestionTypeString() const{ 126 | return CongestionControlTypeToString(cc_type_); 127 | } 128 | std::unique_ptr Ns3QuicClient::CreateQuicClientSession( 129 | const quic::ParsedQuicVersionVector& supported_versions, 130 | QuicConnection* connection){ 131 | std::unique_ptr connection_ptr(connection); 132 | std::unique_ptr session(new Ns3QuicClientSession( 133 | std::move(connection_ptr),owner_,*config(),supported_versions, 134 | server_id(),crypto_config(),backend_)); 135 | session->connection()->sent_packet_manager().SetSendAlgorithm(cc_type_); 136 | return session; 137 | } 138 | int Ns3QuicClient::GetNumSentClientHellosFromSession(){ 139 | return client_session()->GetNumSentClientHellos(); 140 | } 141 | int Ns3QuicClient::GetNumReceivedServerConfigUpdatesFromSession(){ 142 | return client_session()->GetNumReceivedServerConfigUpdates(); 143 | } 144 | bool Ns3QuicClient::EarlyDataAccepted() { 145 | return client_session()->EarlyDataAccepted(); 146 | } 147 | 148 | bool Ns3QuicClient::ReceivedInchoateReject() { 149 | return client_session()->ReceivedInchoateReject(); 150 | } 151 | bool Ns3QuicClient::HasActiveRequests() { 152 | return client_session()->HasActiveRequestStreams(); 153 | } 154 | 155 | } 156 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-client.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "gquiche/quic/core/quic_types.h" 4 | #include "gquiche/quic/tools/quic_client_base.h" 5 | #include "gquiche/quic/core/quic_bandwidth.h" 6 | namespace quic{ 7 | class Ns3QuicBackendBase; 8 | class Ns3QuicPollServer; 9 | class Ns3QuicAlarmEngine; 10 | class Ns3QuicClientSession; 11 | class Ns3QuicClient:public QuicClientBase{ 12 | public: 13 | Ns3QuicClient(QuicSession::Visitor *owner, 14 | QuicSocketAddress server_address, 15 | const QuicServerId& server_id, 16 | const ParsedQuicVersionVector& supported_versions, 17 | std::unique_ptr proof_verifier, 18 | Ns3QuicAlarmEngine *engine, 19 | Ns3QuicBackendBase *backend, 20 | Ns3QuicPollServer *poller, 21 | CongestionControlType cc_type); 22 | Ns3QuicClient(QuicSession::Visitor *owner, 23 | QuicSocketAddress server_address, 24 | const QuicServerId& server_id, 25 | const ParsedQuicVersionVector& supported_versions, 26 | const QuicConfig& config, 27 | std::unique_ptr proof_verifier, 28 | std::unique_ptr session_cache, 29 | Ns3QuicAlarmEngine *engine, 30 | Ns3QuicBackendBase *backend, 31 | Ns3QuicPollServer *poller, 32 | CongestionControlType cc_type); 33 | ~Ns3QuicClient() override; 34 | void AsynConnect(); 35 | Ns3QuicClientSession* client_session(); 36 | bool GetBandwidth(QuicBandwidth &bandwidth) const; 37 | bool GetCongestionWindowBytes(QuicByteCount &bytes) const; 38 | bool GetCongestionWindowPackets(int &packets) const; 39 | bool GetInFlightBytes(QuicByteCount& bytes) const; 40 | bool GetInFlightPackets(int & packets) const; 41 | std::string GetCongestionTypeString() const; 42 | protected: 43 | //from QuicClientBase 44 | // Takes ownership of |connection|. 45 | std::unique_ptr CreateQuicClientSession( 46 | const quic::ParsedQuicVersionVector& supported_versions, 47 | QuicConnection* connection) override; 48 | 49 | int GetNumSentClientHellosFromSession() override; 50 | int GetNumReceivedServerConfigUpdatesFromSession() override; 51 | 52 | // This client does not resend saved data. This will be a no-op. 53 | void ResendSavedData() override{} 54 | 55 | // This client does not resend saved data. This will be a no-op. 56 | void ClearDataToResend() override{} 57 | 58 | bool EarlyDataAccepted() override; 59 | bool ReceivedInchoateReject() override; 60 | bool HasActiveRequests() override; 61 | private: 62 | Ns3QuicBackendBase *backend_=nullptr; 63 | QuicSession::Visitor *owner_=nullptr; 64 | CongestionControlType cc_type_; 65 | }; 66 | } 67 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-clock.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "ns3/simulator.h" 4 | #include "ns3-quic-clock.h" 5 | namespace quic{ 6 | template 7 | class NoDestructor { 8 | public: 9 | // Not constexpr; just write static constexpr T x = ...; if the value should 10 | // be a constexpr. 11 | template 12 | explicit NoDestructor(Args&&... args) { 13 | new (storage_) T(std::forward(args)...); 14 | } 15 | 16 | // Allows copy and move construction of the contained type, to allow 17 | // construction from an initializer list, e.g. for std::vector. 18 | explicit NoDestructor(const T& x) { new (storage_) T(x); } 19 | explicit NoDestructor(T&& x) { new (storage_) T(std::move(x)); } 20 | 21 | NoDestructor(const NoDestructor&) = delete; 22 | NoDestructor& operator=(const NoDestructor&) = delete; 23 | 24 | ~NoDestructor() = default; 25 | 26 | const T& operator*() const { return *get(); } 27 | T& operator*() { return *get(); } 28 | 29 | const T* operator->() const { return get(); } 30 | T* operator->() { return get(); } 31 | 32 | const T* get() const { return reinterpret_cast(storage_); } 33 | T* get() { return reinterpret_cast(storage_); } 34 | 35 | private: 36 | alignas(T) char storage_[sizeof(T)]; 37 | }; 38 | Ns3QuicClock* Ns3QuicClock::Instance(){ 39 | static NoDestructor ins; 40 | return ins.get(); 41 | } 42 | Ns3QuicClock::Ns3QuicClock()=default; 43 | Ns3QuicClock::~Ns3QuicClock()=default; 44 | QuicTime Ns3QuicClock::ApproximateNow() const{ 45 | return Now(); 46 | } 47 | QuicTime Ns3QuicClock::Now() const{ 48 | int64_t now_us=ns3::Simulator::Now().GetMicroSeconds(); 49 | return CreateTimeFromMicroseconds(now_us); 50 | } 51 | QuicWallTime Ns3QuicClock::WallNow() const{ 52 | int64_t now_us=ns3::Simulator::Now().GetMicroSeconds(); 53 | return QuicWallTime::FromUNIXMicroseconds(now_us); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-clock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "gquiche/quic/core/quic_clock.h" 3 | namespace quic{ 4 | class Ns3QuicClock:public QuicClock{ 5 | public: 6 | static Ns3QuicClock*Instance(); 7 | Ns3QuicClock(); 8 | 9 | Ns3QuicClock(const Ns3QuicClock&) = delete; 10 | Ns3QuicClock& operator=(const Ns3QuicClock&) = delete; 11 | 12 | ~Ns3QuicClock() override; 13 | 14 | // QuicClock implementation: 15 | QuicTime ApproximateNow() const override; 16 | QuicTime Now() const override; 17 | QuicWallTime WallNow() const override; 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-congestion-factory.cc: -------------------------------------------------------------------------------- 1 | #include "gquiche/quic/core/congestion_control/bbr2_sender.h" 2 | #include "gquiche/quic/core/congestion_control/bbr_sender.h" 3 | #include "gquiche/quic/core/congestion_control/tcp_cubic_sender_bytes.h" 4 | 5 | #include "ns3/ns3-quic-congestion-factory.h" 6 | #include "ns3-quic-no-destructor.h" 7 | #include "cc-algo/copa_sender.h" 8 | #include "cc-algo/vegas_sender.h" 9 | #include "ns3-quic-private.h" 10 | namespace quic{ 11 | class Ns3QuicCongestionFactory:public AbstractCongestionFactory{ 12 | public: 13 | ~Ns3QuicCongestionFactory() override{} 14 | SendAlgorithmInterface* Create( 15 | const QuicClock* clock, 16 | const RttStats* rtt_stats, 17 | const QuicUnackedPacketMap* unacked_packets, 18 | CongestionControlType type, 19 | QuicRandom* random, 20 | QuicConnectionStats* stats, 21 | QuicPacketCount initial_congestion_window, 22 | QuicPacketCount max_congestion_window, 23 | SendAlgorithmInterface* old_send_algorithm) override; 24 | }; 25 | SendAlgorithmInterface* Ns3QuicCongestionFactory::Create( 26 | const QuicClock* clock, 27 | const RttStats* rtt_stats, 28 | const QuicUnackedPacketMap* unacked_packets, 29 | CongestionControlType type, 30 | QuicRandom* random, 31 | QuicConnectionStats* stats, 32 | QuicPacketCount initial_congestion_window, 33 | QuicPacketCount max_congestion_window, 34 | SendAlgorithmInterface* old_send_algorithm){ 35 | int v=type; 36 | SendAlgorithmInterface *algo=nullptr; 37 | if(kBBR==v){ 38 | algo=new BbrSender(clock->ApproximateNow(), rtt_stats, unacked_packets, 39 | initial_congestion_window, max_congestion_window, 40 | random, stats); 41 | }else if(kBBRv2==v){ 42 | algo=new Bbr2Sender(clock->ApproximateNow(), rtt_stats, unacked_packets, 43 | initial_congestion_window, max_congestion_window, random, stats, 44 | old_send_algorithm && 45 | old_send_algorithm->GetCongestionControlType() == kBBR 46 | ? static_cast(old_send_algorithm) 47 | : nullptr); 48 | }else if(kCubicBytes==v){ 49 | algo=new TcpCubicSenderBytes(clock, rtt_stats, false /* don't use Reno */, 50 | initial_congestion_window, max_congestion_window, stats); 51 | }else if(kCopa==v){ 52 | algo=new CopaSender(clock->ApproximateNow(), rtt_stats, unacked_packets, 53 | initial_congestion_window, max_congestion_window, 54 | random, stats); 55 | }else if(kVegas==v){ 56 | algo=new VegasSender(clock->ApproximateNow(), rtt_stats, unacked_packets, 57 | initial_congestion_window, max_congestion_window, 58 | random, stats); 59 | }else{ 60 | algo=new TcpCubicSenderBytes(clock, rtt_stats, true /* use Reno */, 61 | initial_congestion_window, 62 | max_congestion_window, stats); 63 | } 64 | return algo; 65 | } 66 | Ns3QuicCongestionFactory* CreateCongestionFactory() { 67 | static NoDestructor singleton; 68 | return singleton.get(); 69 | } 70 | void RegisterExternalCongestionFactory(){ 71 | SetCongestionFactory(CreateCongestionFactory()); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-congestion-factory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | namespace quic{ 3 | void RegisterExternalCongestionFactory(); 4 | } 5 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-connection-helper.cc: -------------------------------------------------------------------------------- 1 | #include "gquiche/common/platform/api/quiche_logging.h" 2 | #include "gquiche/quic/core/crypto/quic_random.h" 3 | 4 | #include "ns3-quic-connection-helper.h" 5 | #include "ns3-quic-clock.h" 6 | namespace quic{ 7 | Ns3QuicConnectionHelper::Ns3QuicConnectionHelper(QuicAllocatorType allocator_type): 8 | random_generator_(QuicRandom::GetInstance()), 9 | clock_(Ns3QuicClock::Instance()), 10 | allocator_type_(allocator_type){} 11 | Ns3QuicConnectionHelper::~Ns3QuicConnectionHelper()=default; 12 | const QuicClock* Ns3QuicConnectionHelper::GetClock() const{ 13 | return clock_; 14 | } 15 | 16 | QuicRandom* Ns3QuicConnectionHelper::GetRandomGenerator(){ 17 | return random_generator_; 18 | } 19 | QuicBufferAllocator* Ns3QuicConnectionHelper::GetStreamSendBufferAllocator(){ 20 | if (allocator_type_ == QuicAllocatorType::BUFFER_POOL) { 21 | return &stream_buffer_allocator_; 22 | } else { 23 | QUICHE_DCHECK(allocator_type_ == QuicAllocatorType::SIMPLE); 24 | return &simple_buffer_allocator_; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-connection-helper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "gquiche/quic/core/quic_simple_buffer_allocator.h" 3 | #include "gquiche/quic/platform/api/quic_stream_buffer_allocator.h" 4 | #include "gquiche/quic/core/quic_clock.h" 5 | #include "gquiche/quic/core/quic_connection.h" 6 | namespace quic{ 7 | class QuicRandom; 8 | enum class QuicAllocatorType { SIMPLE, BUFFER_POOL }; 9 | class Ns3QuicConnectionHelper:public QuicConnectionHelperInterface{ 10 | public: 11 | Ns3QuicConnectionHelper(QuicAllocatorType allocator_type); 12 | Ns3QuicConnectionHelper(const Ns3QuicConnectionHelper&) = delete; 13 | Ns3QuicConnectionHelper& operator=(const Ns3QuicConnectionHelper&) =delete; 14 | ~Ns3QuicConnectionHelper() override; 15 | 16 | // QuicConnectionHelperInterface 17 | const QuicClock* GetClock() const override; 18 | QuicRandom* GetRandomGenerator() override; 19 | QuicBufferAllocator* GetStreamSendBufferAllocator() override; 20 | private: 21 | QuicRandom* random_generator_=nullptr; 22 | QuicClock *clock_=nullptr; 23 | // Set up allocators. They take up minimal memory before use. 24 | // Allocator for stream send buffers. 25 | QuicStreamBufferAllocator stream_buffer_allocator_; 26 | SimpleBufferAllocator simple_buffer_allocator_; 27 | QuicAllocatorType allocator_type_; 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-dispatcher.cc: -------------------------------------------------------------------------------- 1 | #include "ns3-quic-dispatcher.h" 2 | #include "ns3-quic-backend.h" 3 | #include "ns3-quic-server-session.h" 4 | namespace quic{ 5 | Ns3QuicDispatcher::Ns3QuicDispatcher( 6 | const QuicConfig* config, 7 | const QuicCryptoServerConfig* crypto_config, 8 | QuicVersionManager* version_manager, 9 | std::unique_ptr helper, 10 | std::unique_ptr session_helper, 11 | std::unique_ptr alarm_factory, 12 | uint8_t expected_server_connection_id_length, 13 | Ns3QuicBackendBase *backend): 14 | QuicDispatcher(config,crypto_config,version_manager,std::move(helper), 15 | std::move(session_helper),std::move(alarm_factory),expected_server_connection_id_length), 16 | backend_(backend){} 17 | 18 | Ns3QuicDispatcher::~Ns3QuicDispatcher()=default; 19 | 20 | int Ns3QuicDispatcher::GetRstErrorCount( 21 | QuicRstStreamErrorCode error_code) const { 22 | auto it = rst_error_map_.find(error_code); 23 | if (it == rst_error_map_.end()) { 24 | return 0; 25 | } 26 | return it->second; 27 | } 28 | void Ns3QuicDispatcher::OnRstStreamReceived(const QuicRstStreamFrame& frame) { 29 | auto it = rst_error_map_.find(frame.error_code); 30 | if (it == rst_error_map_.end()) { 31 | rst_error_map_.insert(std::make_pair(frame.error_code, 1)); 32 | } else { 33 | it->second++; 34 | } 35 | } 36 | std::unique_ptr Ns3QuicDispatcher::CreateQuicSession( 37 | QuicConnectionId server_connection_id, 38 | const QuicSocketAddress& self_address, 39 | const QuicSocketAddress& peer_address, 40 | absl::string_view /*alpn*/, 41 | const ParsedQuicVersion& version, 42 | absl::string_view /*sni*/){ 43 | // The QuicServerSessionBase takes ownership of |connection| below. 44 | std::unique_ptr connection; 45 | connection.reset(new QuicConnection( 46 | server_connection_id,self_address, peer_address, helper(), alarm_factory(), writer(), 47 | /* owns_writer= */ false, Perspective::IS_SERVER,ParsedQuicVersionVector{version})); 48 | 49 | auto session = std::make_unique(std::move(connection),this, 50 | config(), GetSupportedVersions(),crypto_config(), compressed_certs_cache(), 51 | backend_); 52 | session->Initialize(); 53 | return session; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-dispatcher.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "absl/strings/string_view.h" 4 | #include "gquiche/quic/core/quic_dispatcher.h" 5 | namespace quic{ 6 | class Ns3QuicBackendBase; 7 | class Ns3QuicDispatcher:public QuicDispatcher{ 8 | public: 9 | Ns3QuicDispatcher( 10 | const QuicConfig* config, 11 | const QuicCryptoServerConfig* crypto_config, 12 | QuicVersionManager* version_manager, 13 | std::unique_ptr helper, 14 | std::unique_ptr session_helper, 15 | std::unique_ptr alarm_factory, 16 | uint8_t expected_server_connection_id_length, 17 | Ns3QuicBackendBase *backend); 18 | 19 | ~Ns3QuicDispatcher() override; 20 | 21 | int GetRstErrorCount(QuicRstStreamErrorCode rst_error_code) const; 22 | 23 | void OnRstStreamReceived(const QuicRstStreamFrame& frame) override; 24 | //GetSupportedVersions OnConnectionClosed OnWriteBlocked OnStopSendingReceived 25 | protected: 26 | std::unique_ptr CreateQuicSession( 27 | QuicConnectionId server_connection_id, 28 | const QuicSocketAddress& self_address, 29 | const QuicSocketAddress& peer_address, 30 | absl::string_view alpn, 31 | const ParsedQuicVersion& version, 32 | absl::string_view sni) override; 33 | private: 34 | Ns3QuicBackendBase *backend_; 35 | // The map of the reset error code with its counter. 36 | std::map rst_error_map_; 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-flags.cc: -------------------------------------------------------------------------------- 1 | #include "gquiche/quic/platform/api/quic_flags.h" 2 | #include "ns3-quic-flags.h" 3 | DEFINE_QUIC_COMMAND_LINE_FLAG(int32_t, 4 | test_value, 5 | 123, 6 | "Initial MTU of the connection."); 7 | DEFINE_QUIC_COMMAND_LINE_FLAG( 8 | std::string, 9 | quic_version, 10 | "", 11 | "QUIC version to speak, e.g. 21. If not set, then all available " 12 | "versions are offered in the handshake. Also supports wire versions " 13 | "such as Q043 or T099."); 14 | 15 | DEFINE_QUIC_COMMAND_LINE_FLAG(bool, 16 | quic_ietf_draft, 17 | false, 18 | "Use the IETF draft version. This also enables " 19 | "required internal QUIC flags."); 20 | DEFINE_QUIC_COMMAND_LINE_FLAG( 21 | bool, 22 | force_version_negotiation, 23 | false, 24 | "If true, start by proposing a version that is reserved for version " 25 | "negotiation."); 26 | namespace quic{ 27 | int get_test_value(){ 28 | return GetQuicFlag(FLAGS_test_value); 29 | } 30 | std::string get_quic_version(){ 31 | return GetQuicFlag(FLAGS_quic_version); 32 | } 33 | bool get_quic_ietf_draft(){ 34 | return GetQuicFlag(FLAGS_quic_ietf_draft); 35 | } 36 | bool get_force_version_negotiation(){ 37 | return GetQuicFlag(FLAGS_force_version_negotiation); 38 | } 39 | } -------------------------------------------------------------------------------- /quic/model/ns3-quic-flags.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | namespace quic{ 4 | int get_test_value(); 5 | std::string get_quic_version(); 6 | bool get_quic_ietf_draft(); 7 | bool get_force_version_negotiation(); 8 | } -------------------------------------------------------------------------------- /quic/model/ns3-quic-no-destructor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | namespace quic{ 3 | //copy from leveldb 4 | // Wraps an instance whose destructor is never called. 5 | // 6 | // This is intended for use with function-level static variables. 7 | template 8 | class NoDestructor { 9 | public: 10 | template 11 | explicit NoDestructor(ConstructorArgTypes&&... constructor_args) { 12 | static_assert(sizeof(instance_storage_) >= sizeof(InstanceType), 13 | "instance_storage_ is not large enough to hold the instance"); 14 | static_assert( 15 | alignof(decltype(instance_storage_)) >= alignof(InstanceType), 16 | "instance_storage_ does not meet the instance's alignment requirement"); 17 | new (&instance_storage_) 18 | InstanceType(std::forward(constructor_args)...); 19 | } 20 | 21 | ~NoDestructor() = default; 22 | 23 | NoDestructor(const NoDestructor&) = delete; 24 | NoDestructor& operator=(const NoDestructor&) = delete; 25 | 26 | InstanceType* get() { 27 | return reinterpret_cast(&instance_storage_); 28 | } 29 | 30 | private: 31 | typename std::aligned_storage::type instance_storage_; 33 | }; 34 | } -------------------------------------------------------------------------------- /quic/model/ns3-quic-poll-server.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "gquiche/quic/platform/api/quic_socket_address.h" 3 | namespace quic{ 4 | class QuicPacketWriter; 5 | class Ns3PacketInCallback{ 6 | public: 7 | virtual ~Ns3PacketInCallback(){} 8 | virtual void ProcessPacket(const QuicSocketAddress& self_address, 9 | const QuicSocketAddress& peer_address, 10 | const QuicReceivedPacket& packet)=0; 11 | virtual void OnRegistration()=0; 12 | virtual void OnUnregistration()=0; 13 | virtual void OnShutdown()=0; 14 | }; 15 | class Ns3QuicPollServer{ 16 | public: 17 | virtual ~Ns3QuicPollServer(){} 18 | virtual bool CreateUDPSocketAndBind(QuicSocketAddress server_address, 19 | QuicIpAddress bind_to_address, 20 | int bind_to_port)=0; 21 | virtual QuicSocketAddress GetLatestClientAddress() const =0; 22 | 23 | virtual void RegisterFD(Ns3PacketInCallback *cb)=0; 24 | virtual void UnregisterFD(Ns3PacketInCallback *cb)=0; 25 | virtual QuicPacketWriter* CreateQuicPacketWriter()=0; 26 | 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-private.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "gquiche/quic/core/congestion_control/send_algorithm_interface.h" 3 | namespace quic{ 4 | enum CongestionControlType2{ 5 | kCC0=CongestionControlType::kBBRv2, 6 | kCopa, 7 | kVegas, 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-public.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | namespace quic{ 4 | enum class BackendType{ 5 | HELLO_UNIDI, 6 | HELLO_BIDI, 7 | BANDWIDTH 8 | }; 9 | void ContentInit(const char v); 10 | } 11 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-server-app.cc: -------------------------------------------------------------------------------- 1 | #include "gquiche/quic/platform/api/quic_default_proof_providers.h" 2 | #include "gquiche/quic/platform/api/quic_logging.h" 3 | 4 | #include "ns3/log.h" 5 | #include "ns3/assert.h" 6 | #include "ns3-quic-clock.h" 7 | #include "ns3-quic-tag.h" 8 | #include "ns3-quic-flags.h" 9 | #include "ns3-quic-addr-convert.h" 10 | #include "ns3-quic-server-app.h" 11 | #include "ns3-quic-server.h" 12 | #include "ns3-quic-backend.h" 13 | #include "ns3-packet-writer.h" 14 | #include "ns3-quic-alarm-engine.h" 15 | #include "ns3/ns3-quic-trace.h" 16 | #include 17 | namespace ns3{ 18 | 19 | NS_LOG_COMPONENT_DEFINE("QuicServerApp"); 20 | 21 | class QuicServerAppImpl:public quic::Ns3PacketWriter::Delegate{ 22 | public: 23 | QuicServerAppImpl(QuicServerApp *outer,quic::BackendType type); 24 | ~QuicServerAppImpl() override; 25 | 26 | //from quic::Ns3PacketWriter::Delegate 27 | int WritePacket(const char* buffer, 28 | size_t buf_len, 29 | const quic::QuicIpAddress& self_address, 30 | const quic::QuicSocketAddress& peer_address) override; 31 | void OnWriterDestroy() override{} 32 | void OnIncomingData(quic::QuicSocketAddress self_addr, 33 | quic::QuicSocketAddress peer_addr, 34 | const char *buffer, size_t sz); 35 | private: 36 | int Start(); 37 | void Stop(); 38 | QuicServerApp *m_outer=nullptr; 39 | quic::QuicClock *m_clock=nullptr; 40 | std::unique_ptr m_quicServer; 41 | std::unique_ptr m_backend; 42 | std::unique_ptr m_engine; 43 | friend class QuicServerApp; 44 | }; 45 | 46 | QuicServerApp::QuicServerApp(quic::BackendType type){ 47 | m_impl.reset(new QuicServerAppImpl(this,type)); 48 | } 49 | 50 | QuicServerApp::~QuicServerApp(){ 51 | StopApplication(); 52 | if(m_socket){ 53 | m_socket->Close(); 54 | m_socket=nullptr; 55 | } 56 | } 57 | 58 | void QuicServerApp::Bind(uint16_t port){ 59 | if (NULL==m_socket){ 60 | m_socket = Socket::CreateSocket (GetNode (),UdpSocketFactory::GetTypeId ()); 61 | auto local = InetSocketAddress{Ipv4Address::GetAny (),port}; 62 | auto res = m_socket->Bind (local); 63 | NS_ASSERT (res == 0); 64 | Address addr; 65 | m_socket->GetSockName(addr); 66 | InetSocketAddress self_sock_addr=InetSocketAddress::ConvertFrom(addr); 67 | m_bindPort=self_sock_addr.GetPort(); 68 | m_socket->SetRecvCallback (MakeCallback(&QuicServerApp::RecvPacket,this)); 69 | } 70 | } 71 | 72 | InetSocketAddress QuicServerApp::GetLocalAddress() const{ 73 | Ptr node=GetNode(); 74 | Ptr ipv4 = node->GetObject (); 75 | Ipv4Address local_ip = ipv4->GetAddress (1, 0).GetLocal(); 76 | return InetSocketAddress{local_ip,m_bindPort}; 77 | } 78 | 79 | void QuicServerApp::set_trace(Ns3QuicServerTraceDispatcher *trace){ 80 | m_trace=trace; 81 | } 82 | 83 | void QuicServerApp::RecvPacket(Ptr socket){ 84 | if (!m_running) {return ;} 85 | InetSocketAddress ns3_self_sock_addr(m_bindIp,m_bindPort); 86 | quic::QuicSocketAddress quic_self_sock_addr=GetQuicSocketAddr(ns3_self_sock_addr); 87 | 88 | Address remoteAddr; 89 | auto packet = socket->RecvFrom (remoteAddr); 90 | InetSocketAddress ns3_peer_sock_addr=InetSocketAddress::ConvertFrom(remoteAddr); 91 | quic::QuicSocketAddress quic_peer_sock_addr=GetQuicSocketAddr(ns3_peer_sock_addr); 92 | uint32_t length=packet->GetSize(); 93 | //NS_LOG_INFO(this<<" QuicServerApp::recv "<RemovePacketTag(tag); 96 | char buffer[2000]={'\0'}; 97 | packet->CopyData((uint8_t*)buffer,length); 98 | if(m_impl){ 99 | m_impl->OnIncomingData(quic_self_sock_addr,quic_peer_sock_addr,buffer,(size_t)length); 100 | } 101 | 102 | if(m_trace){ 103 | int seq=tag.GetSequence(); 104 | Time now=Simulator::Now(); 105 | int64_t now_ms=now.GetMilliSeconds(); 106 | int64_t sent_time=tag.GetTime(); 107 | int owd=0; 108 | if(now_ms>=sent_time){ 109 | owd=now_ms-sent_time; 110 | } 111 | m_trace->OnOwd(ns3_peer_sock_addr,ns3_self_sock_addr,seq,owd,length); 112 | } 113 | } 114 | 115 | void QuicServerApp::SendToNetwork(const char *buffer,size_t sz,const InetSocketAddress& dest){ 116 | Time now=Simulator::Now(); 117 | Ptr packet=Create((const uint8_t*)buffer,sz); 118 | //NS_LOG_INFO(this<<" QuicServerApp::send "<AddPacketTag(tag); 123 | m_seq++; 124 | m_socket->SendTo(packet,0,dest); 125 | } 126 | 127 | void QuicServerApp::StartApplication(){ 128 | m_running=true; 129 | m_bindIp=GetLocalAddress().GetIpv4(); 130 | if (m_impl) { 131 | m_impl->Start(); 132 | } 133 | } 134 | void QuicServerApp::StopApplication(){ 135 | if(m_trace){ 136 | m_trace->Shutdown(); 137 | m_trace=nullptr; 138 | } 139 | if(m_impl){ 140 | m_impl->Stop(); 141 | } 142 | m_running=false; 143 | } 144 | 145 | QuicServerAppImpl::QuicServerAppImpl(QuicServerApp *outer,quic::BackendType type): 146 | m_outer(outer){ 147 | m_clock=quic::Ns3QuicClock::Instance(); 148 | m_engine.reset(new quic::Ns3QuicAlarmEngine(quic::Perspective::IS_SERVER)); 149 | if(quic::BackendType::HELLO_UNIDI==type||quic::BackendType::HELLO_BIDI==type){ 150 | m_backend.reset(new quic::HelloServerBackend(m_engine.get())); 151 | }else{ 152 | m_backend.reset(new quic::BandwidthServerBackend(m_engine.get())); 153 | } 154 | } 155 | 156 | QuicServerAppImpl::~QuicServerAppImpl(){ 157 | Stop(); 158 | } 159 | 160 | 161 | int QuicServerAppImpl::WritePacket(const char* buffer, 162 | size_t buf_len, 163 | const quic::QuicIpAddress& self_address, 164 | const quic::QuicSocketAddress& peer_address){ 165 | InetSocketAddress ns3_sock_addr=GetNs3SocketAddr(peer_address); 166 | if (m_outer){ 167 | m_outer->SendToNetwork(buffer,buf_len,ns3_sock_addr); 168 | } 169 | return buf_len; 170 | } 171 | void QuicServerAppImpl::OnIncomingData(quic::QuicSocketAddress self_addr, 172 | quic::QuicSocketAddress peer_addr, 173 | const char *buffer, size_t sz){ 174 | quic::QuicTime now=m_clock->Now(); 175 | quic::QuicReceivedPacket quic_packet(buffer,sz,now); 176 | if(m_quicServer){ 177 | m_quicServer->ProcessPacket(self_addr,peer_addr,quic_packet); 178 | } 179 | } 180 | 181 | int QuicServerAppImpl::Start(){ 182 | quic::ParsedQuicVersionVector supported_versions; 183 | if (quic::get_quic_ietf_draft()) { 184 | quic::QuicVersionInitializeSupportForIetfDraft(); 185 | for (const quic::ParsedQuicVersion& version : quic::AllSupportedVersions()) { 186 | // Add all versions that supports IETF QUIC. 187 | if (version.HasIetfQuicFrames() && 188 | version.handshake_protocol == quic::PROTOCOL_TLS1_3) { 189 | supported_versions.push_back(version); 190 | } 191 | } 192 | } else { 193 | supported_versions = quic::AllSupportedVersions(); 194 | } 195 | 196 | std::string versions_string = quic::get_quic_version();; 197 | if (!versions_string.empty()) { 198 | supported_versions = quic::ParseQuicVersionVectorString(versions_string); 199 | } 200 | if (supported_versions.empty()) { 201 | return 1; 202 | } 203 | for (const auto& version : supported_versions) { 204 | quic::QuicEnableVersion(version); 205 | } 206 | auto proof_source = quic::CreateDefaultProofSource(); 207 | QUICHE_CHECK(proof_source!=nullptr); 208 | quic::Ns3QuicAlarmEngine *engine=m_backend->get_engine(); 209 | m_quicServer.reset(new quic::Ns3QuicServer(std::move(proof_source), 210 | engine,m_backend.get())); 211 | quic::QuicPacketWriter *writer=new quic::Ns3PacketWriter(this); 212 | if(!m_quicServer->ConfigureDispatcher(writer)){ 213 | return 1; 214 | } 215 | return 0; 216 | } 217 | void QuicServerAppImpl::Stop(){ 218 | if(m_quicServer){ 219 | m_quicServer->Shutdown(); 220 | } 221 | m_quicServer=nullptr; 222 | m_backend=nullptr; 223 | m_engine=nullptr; 224 | } 225 | 226 | } 227 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-server-app.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "ns3/simulator.h" 5 | #include "ns3/application.h" 6 | #include "ns3/socket.h" 7 | #include "ns3/network-module.h" 8 | #include "ns3/internet-module.h" 9 | #include "ns3/callback.h" 10 | #include "ns3/ns3-quic-public.h" 11 | namespace ns3{ 12 | class QuicServerAppImpl; 13 | class Ns3QuicServerTraceDispatcher; 14 | class QuicServerApp: public Application{ 15 | public: 16 | QuicServerApp(quic::BackendType type=quic::BackendType::HELLO_UNIDI); 17 | ~QuicServerApp() override; 18 | void Bind(uint16_t port); 19 | InetSocketAddress GetLocalAddress() const; 20 | void set_trace(Ns3QuicServerTraceDispatcher *trace); 21 | void SendToNetwork(const char *buffer,size_t sz,const InetSocketAddress& dest); 22 | private: 23 | virtual void StartApplication() override; 24 | virtual void StopApplication() override; 25 | void RecvPacket(Ptr socket); 26 | 27 | std::unique_ptr m_impl; 28 | Ptr m_socket; 29 | Ipv4Address m_bindIp; 30 | uint16_t m_bindPort=0; 31 | Ns3QuicServerTraceDispatcher *m_trace=nullptr; 32 | bool m_running=false; 33 | uint64_t m_seq=1; 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-server-session.cc: -------------------------------------------------------------------------------- 1 | #include "absl/strings/str_cat.h" 2 | #include "absl/strings/string_view.h" 3 | #include "gquiche/quic/core/quic_error_codes.h" 4 | #include "gquiche/quic/core/quic_stream.h" 5 | #include "gquiche/quic/core/quic_types.h" 6 | #include "gquiche/quic/quic_transport/quic_transport_protocol.h" 7 | 8 | #include "ns3-quic-session-base.h" 9 | #include "ns3-transport-stream.h" 10 | #include "ns3-quic-backend.h" 11 | #include "ns3-quic-server-session.h" 12 | namespace quic{ 13 | namespace { 14 | class Ns3QuicTransportServerCryptoHelper 15 | : public QuicCryptoServerStreamBase::Helper { 16 | public: 17 | bool CanAcceptClientHello(const CryptoHandshakeMessage& /*message*/, 18 | const QuicSocketAddress& /*client_address*/, 19 | const QuicSocketAddress& /*peer_address*/, 20 | const QuicSocketAddress& /*self_address*/, 21 | std::string* /*error_details*/) const override { 22 | return true; 23 | } 24 | }; 25 | 26 | } // namespace 27 | Ns3QuicServerSession::Ns3QuicServerSession( 28 | std::unique_ptr connection_ptr, 29 | Visitor* owner, 30 | const QuicConfig& config, 31 | const ParsedQuicVersionVector& supported_versions, 32 | const QuicCryptoServerConfig* crypto_config, 33 | QuicCompressedCertsCache* compressed_certs_cache, 34 | Ns3QuicBackendBase *backend): 35 | Ns3QuicSessionBase(connection_ptr.get(),owner,config,supported_versions,0), 36 | backend_(backend), 37 | connection_own_(std::move(connection_ptr)){ 38 | /*for (const ParsedQuicVersion& version : supported_versions){ 39 | QUIC_BUG_IF(Ns3QuicServerSession,version.handshake_protocol != PROTOCOL_TLS1_3) 40 | << "QuicTransport requires TLS 1.3 handshake"; 41 | }*/ 42 | static Ns3QuicTransportServerCryptoHelper* helper =new Ns3QuicTransportServerCryptoHelper(); 43 | crypto_stream_ = CreateCryptoServerStream( 44 | crypto_config, compressed_certs_cache,this, helper); 45 | } 46 | Ns3QuicServerSession::~Ns3QuicServerSession(){ 47 | if(endpoint_){ 48 | endpoint_->OnSessionDestroy(this); 49 | } 50 | } 51 | Ns3TransportStream* Ns3QuicServerSession::OpenOutgoingBidirectionalStream(){ 52 | if (!CanOpenNextOutgoingBidirectionalStream()) { 53 | QUIC_BUG(Ns3QuicServerSession)<< "Attempted to open a stream in violation of flow control"; 54 | return nullptr; 55 | } 56 | return CreateStream(GetNextOutgoingBidirectionalStreamId()); 57 | } 58 | Ns3TransportStream* Ns3QuicServerSession::OpenOutgoingUnidirectionalStream(){ 59 | if (!CanOpenNextOutgoingUnidirectionalStream()) { 60 | QUIC_BUG(Ns3QuicServerSession)<< "Attempted to open a stream in violation of flow control"; 61 | return nullptr; 62 | } 63 | return CreateStream(GetNextOutgoingUnidirectionalStreamId()); 64 | } 65 | QuicStream* Ns3QuicServerSession::CreateIncomingStream(QuicStreamId id){ 66 | Ns3TransportStream *stream=nullptr; 67 | if(!ready_&&!endpoint_){ 68 | ready_=true; 69 | endpoint_.reset(backend_->CreateEndpoint(this)); 70 | if(!endpoint_){ 71 | CloseSession(); 72 | return stream; 73 | } 74 | endpoint_->OnSessionReady(this); 75 | } 76 | stream=CreateStream(id); 77 | if(BIDIRECTIONAL==stream->type()){ 78 | endpoint_->OnIncomingBidirectionalStream(stream); 79 | }else{ 80 | endpoint_->OnIncomingUnidirectionalStream(stream); 81 | } 82 | return stream; 83 | } 84 | QuicStream* Ns3QuicServerSession::CreateIncomingStream(PendingStream* /*pending*/){ 85 | return nullptr; 86 | } 87 | void Ns3QuicServerSession::CloseSession(){ 88 | if(connection()&&connection()->connected()){ 89 | connection()->CloseConnection( 90 | QUIC_PEER_GOING_AWAY,"Session disconnecting", 91 | ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); 92 | } 93 | } 94 | Ns3TransportStream* Ns3QuicServerSession::CreateStream(QuicStreamId id){ 95 | auto stream = std::make_unique(id, this); 96 | Ns3TransportStream* stream_ptr = stream.get(); 97 | ActivateStream(std::move(stream)); 98 | return stream_ptr; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-server-session.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "absl/strings/string_view.h" 7 | #include "gquiche/quic/core/quic_connection.h" 8 | #include "gquiche/quic/core/quic_crypto_server_stream_base.h" 9 | #include "gquiche/quic/core/quic_session.h" 10 | #include "gquiche/quic/quic_transport/quic_transport_protocol.h" 11 | 12 | #include "ns3-quic-session-base.h" 13 | namespace quic{ 14 | class Ns3QuicBackendBase; 15 | class Ns3QuicEndpointBase; 16 | class Ns3QuicServerSession:public Ns3QuicSessionBase{ 17 | public: 18 | Ns3QuicServerSession(std::unique_ptr connection_ptr, 19 | Visitor* owner, 20 | const QuicConfig& config, 21 | const ParsedQuicVersionVector& supported_versions, 22 | const QuicCryptoServerConfig* crypto_config, 23 | QuicCompressedCertsCache* compressed_certs_cache, 24 | Ns3QuicBackendBase *backend); 25 | ~Ns3QuicServerSession() override; 26 | //from Ns3QuicSessionBase 27 | Ns3TransportStream* OpenOutgoingBidirectionalStream() override; 28 | Ns3TransportStream* OpenOutgoingUnidirectionalStream() override; 29 | 30 | std::vector::const_iterator SelectAlpn( 31 | const std::vector& alpns) const override { 32 | return std::find(alpns.cbegin(), alpns.cend(), QuicTransportAlpn()); 33 | } 34 | bool ShouldKeepConnectionAlive() const override { return true; } 35 | 36 | QuicCryptoServerStreamBase* GetMutableCryptoStream() override { 37 | return crypto_stream_.get(); 38 | } 39 | const QuicCryptoServerStreamBase* GetCryptoStream() const override { 40 | return crypto_stream_.get(); 41 | } 42 | QuicStream* CreateIncomingStream(QuicStreamId id) override; 43 | QuicStream* CreateIncomingStream(PendingStream* /*pending*/) override; 44 | 45 | bool IsSessionReady() const { return ready_; } 46 | protected: 47 | void CloseSession(); 48 | Ns3TransportStream* CreateStream(QuicStreamId id); 49 | Ns3QuicBackendBase *backend_=nullptr; 50 | std::unique_ptr endpoint_=nullptr; 51 | std::unique_ptr connection_own_; 52 | std::unique_ptr crypto_stream_; 53 | bool ready_=false; 54 | }; 55 | } 56 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-server.cc: -------------------------------------------------------------------------------- 1 | #include "gquiche/quic/core/quic_crypto_server_stream_base.h" 2 | #include "gquiche/quic/core/quic_connection_id.h" 3 | #include "gquiche/quic/core/crypto/quic_random.h" 4 | #include "gquiche/quic/core/quic_constants.h" 5 | #include "gquiche/common/platform/api/quiche_logging.h" 6 | 7 | #include "ns3-quic-backend.h" 8 | #include "ns3-quic-server.h" 9 | #include "ns3-quic-dispatcher.h" 10 | #include "ns3-quic-alarm-engine.h" 11 | #include "ns3-quic-connection-helper.h" 12 | #include "ns3-quic-clock.h" 13 | namespace quic{ 14 | namespace { 15 | const char kSourceAddressTokenSecret[] = "secret"; 16 | const size_t kNumSessionsToCreatePerSocketEvent = 16; 17 | // If an initial flow control window has not explicitly been set, then use a 18 | // sensible value for a server: 1 MB for session, 64 KB for each stream. 19 | const uint32_t kInitialSessionFlowControlWindow = 1 * 1024 * 1024; // 1 MB 20 | const uint32_t kInitialStreamFlowControlWindow = 64 * 1024; // 64 KB 21 | } 22 | class Ns3QuicCryptoServerStreamHelper 23 | : public QuicCryptoServerStreamBase::Helper { 24 | public: 25 | Ns3QuicCryptoServerStreamHelper(){} 26 | 27 | ~Ns3QuicCryptoServerStreamHelper() override{} 28 | 29 | bool CanAcceptClientHello(const CryptoHandshakeMessage& message, 30 | const QuicSocketAddress& client_address, 31 | const QuicSocketAddress& peer_address, 32 | const QuicSocketAddress& self_address, 33 | std::string* error_details) const override{ 34 | return true; 35 | } 36 | }; 37 | 38 | Ns3QuicServer::Ns3QuicServer(std::unique_ptr proof_source, 39 | Ns3QuicAlarmEngine *engine, 40 | Ns3QuicBackendBase *backend): 41 | Ns3QuicServer(std::move(proof_source), 42 | AllSupportedVersions(), 43 | engine, 44 | backend){} 45 | 46 | Ns3QuicServer::Ns3QuicServer(std::unique_ptr proof_source, 47 | const ParsedQuicVersionVector& supported_versions, 48 | Ns3QuicAlarmEngine *engine, 49 | Ns3QuicBackendBase *backend): 50 | Ns3QuicServer(std::move(proof_source), 51 | QuicConfig(), 52 | QuicCryptoServerConfig::ConfigOptions(), 53 | supported_versions, 54 | kQuicDefaultConnectionIdLength, 55 | engine, 56 | backend){} 57 | 58 | Ns3QuicServer::Ns3QuicServer(std::unique_ptr proof_source, 59 | const QuicConfig& config, 60 | const QuicCryptoServerConfig::ConfigOptions& crypto_config_options, 61 | const ParsedQuicVersionVector& supported_versions, 62 | uint8_t expected_server_connection_id_length, 63 | Ns3QuicAlarmEngine *engine, 64 | Ns3QuicBackendBase *backend): 65 | config_(config), 66 | crypto_config_(kSourceAddressTokenSecret, 67 | QuicRandom::GetInstance(), 68 | std::move(proof_source), 69 | KeyExchangeSource::Default()), 70 | crypto_config_options_(crypto_config_options), 71 | version_manager_(supported_versions), 72 | expected_server_connection_id_length_(expected_server_connection_id_length), 73 | engine_(engine), 74 | backend_(backend) 75 | { 76 | clock_=Ns3QuicClock::Instance(); 77 | Initialize(); 78 | } 79 | 80 | Ns3QuicServer::~Ns3QuicServer()=default; 81 | 82 | void Ns3QuicServer::ProcessPacket(const QuicSocketAddress& self_address, 83 | const QuicSocketAddress& peer_address, 84 | const QuicReceivedPacket& packet){ 85 | //TODO 86 | if(dispatcher_){ 87 | dispatcher_->ProcessBufferedChlos(kNumSessionsToCreatePerSocketEvent); 88 | dispatcher_->ProcessPacket(self_address,peer_address,packet); 89 | } 90 | } 91 | void Ns3QuicServer::Shutdown(){ 92 | if(dispatcher_){ 93 | dispatcher_->Shutdown(); 94 | } 95 | } 96 | bool Ns3QuicServer::ConfigureDispatcher(QuicPacketWriter *writer){ 97 | bool ret=false; 98 | if(!dispatcher_){ 99 | QUICHE_DCHECK(writer!=nullptr); 100 | dispatcher_.reset(CreateQuicDispatcher()); 101 | dispatcher_->InitializeWithWriter(writer); 102 | ret=true; 103 | } 104 | return ret; 105 | } 106 | QuicDispatcher* Ns3QuicServer::CreateQuicDispatcher(){ 107 | std::unique_ptr alarm_factory(new Ns3AlarmFactory(engine_)); 108 | std::unique_ptr session_helper(new Ns3QuicCryptoServerStreamHelper); 109 | return new Ns3QuicDispatcher(&config_, 110 | &crypto_config_, 111 | &version_manager_, 112 | std::make_unique(QuicAllocatorType::BUFFER_POOL), 113 | std::move(session_helper), 114 | std::move(alarm_factory), 115 | expected_server_connection_id_length_, 116 | backend_); 117 | } 118 | void Ns3QuicServer::Initialize(){ 119 | if (config_.GetInitialStreamFlowControlWindowToSend() == 120 | kDefaultFlowControlSendWindow) { 121 | config_.SetInitialStreamFlowControlWindowToSend( 122 | kInitialStreamFlowControlWindow); 123 | } 124 | if (config_.GetInitialSessionFlowControlWindowToSend() == 125 | kDefaultFlowControlSendWindow) { 126 | config_.SetInitialSessionFlowControlWindowToSend( 127 | kInitialSessionFlowControlWindow); 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-server.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "absl/strings/string_view.h" 4 | #include "gquiche/quic/core/quic_packet_writer.h" 5 | #include "gquiche/quic/core/crypto/quic_crypto_server_config.h" 6 | #include "gquiche/quic/core/quic_config.h" 7 | #include "gquiche/quic/core/quic_version_manager.h" 8 | #include "gquiche/quic/core/crypto/proof_source.h" 9 | namespace quic{ 10 | class QuicDispatcher; 11 | class Ns3QuicAlarmEngine; 12 | class Ns3QuicBackendBase; 13 | class Ns3QuicServer{ 14 | public: 15 | Ns3QuicServer(std::unique_ptr proof_source, 16 | Ns3QuicAlarmEngine *engine, 17 | Ns3QuicBackendBase *backend); 18 | Ns3QuicServer(std::unique_ptr proof_source, 19 | const ParsedQuicVersionVector& supported_versions, 20 | Ns3QuicAlarmEngine *engine, 21 | Ns3QuicBackendBase *backend); 22 | Ns3QuicServer(std::unique_ptr proof_source, 23 | const QuicConfig& config, 24 | const QuicCryptoServerConfig::ConfigOptions& crypto_config_options, 25 | const ParsedQuicVersionVector& supported_versions, 26 | uint8_t expected_server_connection_id_length, 27 | Ns3QuicAlarmEngine *engine, 28 | Ns3QuicBackendBase *backend); 29 | Ns3QuicServer(const Ns3QuicServer&) = delete; 30 | Ns3QuicServer& operator=(const Ns3QuicServer&) = delete; 31 | ~Ns3QuicServer(); 32 | 33 | void ProcessPacket(const QuicSocketAddress& self_address, 34 | const QuicSocketAddress& peer_address, 35 | const QuicReceivedPacket& packet); 36 | void Shutdown(); 37 | bool ConfigureDispatcher(QuicPacketWriter *writer); 38 | protected: 39 | virtual QuicDispatcher* CreateQuicDispatcher(); 40 | private: 41 | void Initialize(); 42 | // config_ contains non-crypto parameters that are negotiated in the crypto 43 | // handshake. 44 | QuicConfig config_; 45 | // crypto_config_ contains crypto parameters for the handshake. 46 | QuicCryptoServerConfig crypto_config_; 47 | // crypto_config_options_ contains crypto parameters for the handshake. 48 | QuicCryptoServerConfig::ConfigOptions crypto_config_options_; 49 | 50 | // Used to generate current supported versions. 51 | QuicVersionManager version_manager_; 52 | uint8_t expected_server_connection_id_length_; 53 | Ns3QuicAlarmEngine *engine_=nullptr; 54 | Ns3QuicBackendBase *backend_=nullptr; 55 | QuicClock *clock_=nullptr; 56 | std::unique_ptr dispatcher_; 57 | 58 | }; 59 | } 60 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-session-base.cc: -------------------------------------------------------------------------------- 1 | #include "ns3-quic-session-base.h" 2 | #include 3 | namespace quic{ 4 | Ns3QuicSessionBase::Ns3QuicSessionBase(QuicConnection* connection, 5 | QuicSession::Visitor* owner, 6 | const QuicConfig& config, 7 | const ParsedQuicVersionVector& supported_versions, 8 | QuicStreamCount num_expected_unidirectional_static_streams) 9 | :QuicSession(connection,owner,config, 10 | supported_versions,num_expected_unidirectional_static_streams){} 11 | } 12 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-session-base.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "absl/strings/string_view.h" 4 | #include "ns3-transport-stream.h" 5 | #include "gquiche/quic/core/quic_session.h" 6 | namespace quic{ 7 | class Ns3QuicSessionBase:public QuicSession{ 8 | public: 9 | Ns3QuicSessionBase(QuicConnection* connection, 10 | QuicSession::Visitor* owner, 11 | const QuicConfig& config, 12 | const ParsedQuicVersionVector& supported_versions, 13 | QuicStreamCount num_expected_unidirectional_static_streams); 14 | Ns3QuicSessionBase(const Ns3QuicSessionBase&) = delete; 15 | Ns3QuicSessionBase& operator=(const Ns3QuicSessionBase&) = delete; 16 | ~Ns3QuicSessionBase() override{} 17 | using QuicSession::CanOpenNextOutgoingBidirectionalStream; 18 | using QuicSession::CanOpenNextOutgoingUnidirectionalStream; 19 | virtual Ns3TransportStream* OpenOutgoingBidirectionalStream() {return nullptr;} 20 | virtual Ns3TransportStream* OpenOutgoingUnidirectionalStream() {return nullptr;} 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-tag.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "ns3-quic-tag.h" 3 | #include "ns3/core-module.h" 4 | namespace ns3{ 5 | size_t varint_length(uint64_t number){ 6 | int64_t next=number; 7 | size_t key=0; 8 | if(next){ 9 | do{ 10 | next=next/128; 11 | key++; 12 | }while(next>0); 13 | } 14 | return key; 15 | } 16 | TypeId Ns3QuicTag::GetTypeId (void){ 17 | static TypeId tid = TypeId ("ns3::Ns3QuicTag") 18 | .SetParent () 19 | .AddConstructor () 20 | .AddAttribute ("Time", 21 | "time stamp", 22 | EmptyAttributeValue (), 23 | MakeUintegerAccessor (&Ns3QuicTag::GetTime), 24 | MakeUintegerChecker ()) 25 | .AddAttribute ("Number", 26 | "sequence number", 27 | EmptyAttributeValue (), 28 | MakeUintegerAccessor (&Ns3QuicTag::GetSequence), 29 | MakeUintegerChecker ()) 30 | ; 31 | return tid; 32 | } 33 | TypeId Ns3QuicTag::GetInstanceTypeId (void) const{ 34 | return GetTypeId (); 35 | } 36 | uint32_t Ns3QuicTag::GetSerializedSize (void) const { 37 | return varint_length(seq_)+varint_length(time_); 38 | } 39 | void Ns3QuicTag::Serialize (TagBuffer i) const{ 40 | VarintEncode(i,seq_); 41 | VarintEncode(i,time_); 42 | } 43 | void Ns3QuicTag::Deserialize (TagBuffer i){ 44 | VarientDecode(i,&seq_); 45 | VarientDecode(i,&time_); 46 | } 47 | void Ns3QuicTag::VarintEncode(TagBuffer &i,uint64_t value) const{ 48 | char first=0; 49 | uint64_t next=value; 50 | if(next){ 51 | do{ 52 | uint8_t byte=0; 53 | first=next%128; 54 | next=next/128; 55 | byte=first; 56 | if(next>0){ 57 | byte|=128; 58 | } 59 | i.WriteU8(byte); 60 | }while(next>0); 61 | } 62 | } 63 | void Ns3QuicTag::VarientDecode(TagBuffer &i,uint64_t *value){ 64 | uint64_t remain=0; 65 | uint64_t remain_multi=1; 66 | uint8_t byte=0; 67 | do{ 68 | byte=i.ReadU8(); 69 | remain+=(byte&127)*remain_multi; 70 | remain_multi*=128; 71 | }while(byte&128); 72 | *value=remain; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-tag.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "ns3/tag.h" 4 | namespace ns3{ 5 | class Ns3QuicTag:public Tag{ 6 | public: 7 | Ns3QuicTag(){} 8 | Ns3QuicTag(uint64_t seq,uint64_t time):seq_(seq),time_(time){} 9 | static TypeId GetTypeId (void); 10 | virtual TypeId GetInstanceTypeId (void) const override; 11 | virtual uint32_t GetSerializedSize (void) const override; 12 | virtual void Serialize (TagBuffer i) const override; 13 | virtual void Deserialize (TagBuffer i) override; 14 | virtual void Print (std::ostream &os) const override {} 15 | uint64_t GetSequence() const {return seq_;} 16 | void Sequence(uint64_t seq) {seq_=seq;} 17 | uint64_t GetTime() const {return time_;} 18 | void Time(uint64_t now) {time_=now;} 19 | private: 20 | void VarintEncode(TagBuffer &i,uint64_t value) const; 21 | void VarientDecode(TagBuffer &i,uint64_t *value); 22 | uint64_t seq_=0; 23 | uint64_t time_=0; 24 | }; 25 | } -------------------------------------------------------------------------------- /quic/model/ns3-quic-trace.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "ns3/simulator.h" 5 | #include "ns3-quic-trace.h" 6 | #include "ns3-quic-util.h" 7 | namespace ns3{ 8 | namespace{ 9 | std::string Ns3QuicTracePath; 10 | int g_uuid=1; 11 | Time g_goodputInterval=MilliSeconds(1000); 12 | } 13 | static inline int uuid_allocator(){ 14 | return g_uuid++; 15 | } 16 | void set_quic_trace_folder(const std::string &path){ 17 | int len=path.size(); 18 | if(len&&Ns3QuicTracePath[len-1]!='/'){ 19 | Ns3QuicTracePath=path+'/'; 20 | }else{ 21 | Ns3QuicTracePath=path; 22 | } 23 | } 24 | void set_quic_goodput_interval(Time interval){ 25 | g_goodputInterval=interval; 26 | } 27 | Ns3QuicClientTrace::Ns3QuicClientTrace(){ 28 | m_uuid=uuid_allocator(); 29 | } 30 | Ns3QuicClientTrace::~Ns3QuicClientTrace(){ 31 | Close(); 32 | } 33 | 34 | void Ns3QuicClientTrace::LogEnable(const std::string &prefix,QuicClientTraceType e){ 35 | char buf[FILENAME_MAX]; 36 | memset(buf,0,FILENAME_MAX); 37 | std::string name; 38 | if(0==Ns3QuicTracePath.size()){ 39 | name=std::string (getcwd(buf, FILENAME_MAX))+ 40 | "/traces/"+prefix; 41 | }else{ 42 | name=std::string(Ns3QuicTracePath)+prefix; 43 | } 44 | if(e&E_QC_CWND){ 45 | OpenCwndFile(name); 46 | } 47 | if(e&E_QC_IN_FLIGHT){ 48 | OpenInFlightFile(name); 49 | } 50 | if(e&E_QC_SEND_RATE){ 51 | OpenRateFile(name); 52 | } 53 | } 54 | void Ns3QuicClientTrace::OnSendRate(float v){ 55 | if(m_rate.is_open()){ 56 | float now=Simulator::Now().GetSeconds(); 57 | m_rate<m_lastSeq-1){ 138 | int lost=seq-m_lastSeq-1; 139 | m_lostPackets+=lost; 140 | } 141 | if(seq>m_lastSeq){ 142 | m_lastSeq=seq; 143 | } 144 | if(seq>m_largestSeq){ 145 | m_largestSeq=seq; 146 | } 147 | } 148 | } 149 | void Ns3QuicServerTrace::OpenOwdFile(const std::string& name){ 150 | std::string path_name=name+"_owd.txt"; 151 | m_owd.open(path_name.c_str(), std::fstream::out); 152 | } 153 | void Ns3QuicServerTrace::OpenLostFile(const std::string& name){ 154 | std::string path_name=name+"_lost.txt"; 155 | m_lost.open(path_name.c_str(), std::fstream::out); 156 | } 157 | void Ns3QuicServerTrace::OpenGoodputFile(const std::string& name){ 158 | std::string path_name=name+"_goodput.txt"; 159 | m_goodput.open(path_name.c_str(), std::fstream::out); 160 | } 161 | void Ns3QuicServerTrace::LogLostPackets(){ 162 | if(m_lost.is_open()){ 163 | float ratio=0.0; 164 | if(m_largestSeq>0){ 165 | ratio=1.0*m_lostPackets*100/m_largestSeq; 166 | } 167 | m_lost<m_lastRateTime){ 174 | Time delta=m_receiptTime-m_lastRateTime; 175 | float kbps=1.0*(m_readBytes-m_lastRateBytes)*8/delta.GetMilliSeconds(); 176 | m_goodput<=m_lastRateTime+g_goodputInterval){ 180 | Time delta=m_receiptTime-m_lastRateTime; 181 | float kbps=1.0*(m_readBytes-m_lastRateBytes)*8/delta.GetMilliSeconds(); 182 | m_goodput<second; 208 | m_traceDb.erase(it); 209 | delete trace; 210 | } 211 | } 212 | void Ns3QuicServerTraceDispatcher::LogEnable(std::string &topo_id,QuicServerTraceType e){ 213 | m_topoId=topo_id; 214 | m_e=e; 215 | if(E_QS_UTIL&&e){ 216 | OpenUtilFile(topo_id); 217 | } 218 | } 219 | bool Ns3QuicServerTraceDispatcher::AddMonitorAddressPair(const Ns3QuicAddressPair &addr_pair){ 220 | bool success=false; 221 | auto it=m_traceDb.find(addr_pair); 222 | if(it==m_traceDb.end()){ 223 | std::string prefix=m_topoId+"_"+Ns3QuicAddressPair2String(addr_pair); 224 | Ns3QuicServerTrace *trace=new Ns3QuicServerTrace(prefix,m_e); 225 | m_traceDb.insert(std::make_pair(addr_pair,trace)); 226 | success=true; 227 | } 228 | return success; 229 | } 230 | void Ns3QuicServerTraceDispatcher::OnOwd(const InetSocketAddress &c,const InetSocketAddress & s,int seq,int owd,int len){ 231 | Time now=Simulator::Now(); 232 | m_readBytes+=len; 233 | if(Time(0)==m_firstPacketTime){ 234 | m_firstPacketTime=now; 235 | } 236 | m_receiptTime=now; 237 | Ns3QuicAddressPair addr_pair(c,s); 238 | auto it=m_traceDb.find(addr_pair); 239 | if(it!=m_traceDb.end()){ 240 | it->second->OnOwd(seq,owd,len); 241 | } 242 | } 243 | 244 | void Ns3QuicServerTraceDispatcher::CalculateUtil(int64_t channel_bit){ 245 | if (f_util.is_open() && channel_bit > 0) { 246 | float util=1.0*m_readBytes*8*100/(channel_bit); 247 | f_util< 3 | #include 4 | #include 5 | #include "ns3/nstime.h" 6 | #include "ns3/inet-socket-address.h" 7 | #include "ns3/callback.h" 8 | #include "ns3/data-rate.h" 9 | #include "ns3/ns3-quic-addr-pair.h" 10 | namespace ns3{ 11 | //log name format: topoid_ip1:port_ip2:port_type.txt 12 | typedef uint8_t QuicClientTraceType; 13 | typedef uint8_t QuicServerTraceType; 14 | enum QuicClientTraceEnable:uint8_t{ 15 | E_QC_NONE=0x00, 16 | E_QC_CWND=0x01, 17 | E_QC_IN_FLIGHT=0x02, 18 | E_QC_SEND_RATE=0x04, 19 | E_QC_ALL=E_QC_CWND|E_QC_IN_FLIGHT|E_QC_SEND_RATE, 20 | }; 21 | enum QuicServerTraceEnable:uint8_t{ 22 | E_QS_NONE=0x00, 23 | E_QS_OWD=0x01, 24 | E_QS_GOODPUT=0x02, 25 | E_QS_LOST=0x04, 26 | E_QS_UTIL=0x08, 27 | E_QS_ALL=E_QS_OWD|E_QS_GOODPUT|E_QS_LOST|E_QS_UTIL, 28 | }; 29 | void set_quic_trace_folder(const std::string &path); 30 | void set_quic_goodput_interval(Time interval); 31 | class Ns3QuicClientTrace{ 32 | public: 33 | Ns3QuicClientTrace(); 34 | ~Ns3QuicClientTrace(); 35 | void LogEnable(const std::string &prefix,QuicClientTraceType e); 36 | void OnSendRate(float v); 37 | void OnCwnd(int v); 38 | void OnInFlight(int v); 39 | private: 40 | void OpenCwndFile(const std::string& name); 41 | void OpenInFlightFile(const std::string& name); 42 | void OpenRateFile(const std::string& name); 43 | void Close(); 44 | int m_uuid; 45 | std::fstream m_rate; 46 | std::fstream m_cwnd; 47 | std::fstream m_inFlight; 48 | }; 49 | class Ns3QuicServerTrace{ 50 | public: 51 | Ns3QuicServerTrace(std::string &prefix,QuicServerTraceType e); 52 | ~Ns3QuicServerTrace(); 53 | void OnOwd(int seq,int owd,int len); 54 | private: 55 | void OpenOwdFile(const std::string& name); 56 | void OpenLostFile(const std::string& name); 57 | void OpenGoodputFile(const std::string& name); 58 | void LogLostPackets(); 59 | void LogGoodput(bool dtor); 60 | void Close(); 61 | int m_lastSeq=0; 62 | int m_largestSeq=0; 63 | int m_lostPackets=0; 64 | int64_t m_lastRateBytes=0; 65 | Time m_lastRateTime=Time(0); 66 | int64_t m_readBytes=0; 67 | Time m_firstPacketTime=Time(0); 68 | Time m_receiptTime=Time(0); 69 | std::fstream m_owd; 70 | std::fstream m_lost; 71 | std::fstream m_goodput; 72 | }; 73 | class Ns3QuicServerTraceDispatcher{ 74 | public: 75 | Ns3QuicServerTraceDispatcher(); 76 | ~Ns3QuicServerTraceDispatcher(); 77 | void Shutdown(); 78 | void LogEnable(std::string &topo_id,QuicServerTraceType e); 79 | bool AddMonitorAddressPair(const Ns3QuicAddressPair &addr_pair); 80 | void OnOwd(const InetSocketAddress &c,const InetSocketAddress & s,int seq,int owd,int len); 81 | Time GetLastReceiptTime() const{return m_receiptTime;} 82 | void CalculateUtil(int64_t channel_bit); 83 | private: 84 | void OpenUtilFile(const std::string& topo_id); 85 | std::string m_topoId; 86 | QuicServerTraceType m_e=E_QS_NONE; 87 | int64_t m_readBytes=0; 88 | Time m_firstPacketTime=Time(0); 89 | Time m_receiptTime=Time(0); 90 | std::map m_traceDb; 91 | std::fstream f_util; 92 | }; 93 | } 94 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-util.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include // access 6 | #include // stat 7 | #include "gquiche/quic/platform/api/quic_flags.h" 8 | #include "spdlog/sinks/stdout_color_sinks.h" 9 | #include "gquiche/quic/platform/api/quic_logging.h" 10 | #include "ns3-quic-addr-convert.h" 11 | #include "ns3/ns3-quic-util.h" 12 | namespace ns3{ 13 | namespace{ 14 | static bool quic_log_level_setted=false; 15 | static std::string colon(":"); 16 | static std::string undeline("_"); 17 | static std::string period("."); 18 | } 19 | //https://stackoverflow.com/questions/675039/how-can-i-create-directory-tree-in-c-linux 20 | static bool IsDirExist(const std::string& path) 21 | { 22 | #if defined(_WIN32) 23 | struct _stat info; 24 | if (_stat(path.c_str(), &info) != 0) 25 | { 26 | return false; 27 | } 28 | return (info.st_mode & _S_IFDIR) != 0; 29 | #else 30 | struct stat info; 31 | if (stat(path.c_str(), &info) != 0) 32 | { 33 | return false; 34 | } 35 | return (info.st_mode & S_IFDIR) != 0; 36 | #endif 37 | } 38 | 39 | bool MakePath(const std::string& path) 40 | { 41 | #if defined(_WIN32) 42 | int ret = _mkdir(path.c_str()); 43 | #else 44 | mode_t mode = 0755; 45 | int ret = mkdir(path.c_str(), mode); 46 | #endif 47 | if (ret == 0) 48 | return true; 49 | 50 | switch (errno) 51 | { 52 | case ENOENT: 53 | // parent didn't exist, try to create it 54 | { 55 | int pos = path.find_last_of('/'); 56 | if (pos == std::string::npos) 57 | #if defined(_WIN32) 58 | pos = path.find_last_of('\\'); 59 | if (pos == std::string::npos) 60 | #endif 61 | return false; 62 | if (!MakePath( path.substr(0, pos) )) 63 | return false; 64 | } 65 | // now, try to create again 66 | #if defined(_WIN32) 67 | return 0 == _mkdir(path.c_str()); 68 | #else 69 | return 0 == mkdir(path.c_str(), mode); 70 | #endif 71 | case EEXIST: 72 | // done! 73 | return IsDirExist(path); 74 | 75 | default: 76 | return false; 77 | } 78 | } 79 | 80 | void GetFiles(std::string &cate_dir,std::vector &files) 81 | { 82 | DIR *dir; 83 | struct dirent *ptr; 84 | if ((dir=opendir(cate_dir.c_str())) == NULL){ 85 | perror("Open dir error..."); 86 | exit(1); 87 | } 88 | 89 | while ((ptr=readdir(dir)) != NULL) 90 | { 91 | if(strcmp(ptr->d_name,".")==0 || strcmp(ptr->d_name,"..")==0) ///current dir OR parrent dir 92 | continue; 93 | else if(ptr->d_type == 8) ///file 94 | //printf("d_name:%s/%s\n",basePath,ptr->d_name); 95 | files.push_back(ptr->d_name); 96 | else if(ptr->d_type == 10) ///link file 97 | //printf("d_name:%s/%s\n",basePath,ptr->d_name); 98 | continue; 99 | else if(ptr->d_type == 4) ///dir 100 | { 101 | files.push_back(ptr->d_name); 102 | } 103 | } 104 | closedir(dir); 105 | } 106 | 107 | static inline int64_t WallTimeNowInUsec(){ 108 | std::chrono::system_clock::duration d = std::chrono::system_clock::now().time_since_epoch(); 109 | std::chrono::microseconds mic = std::chrono::duration_cast(d); 110 | return mic.count(); 111 | } 112 | 113 | int WallTimeMillis(){ 114 | return WallTimeNowInUsec()/1000; 115 | } 116 | 117 | quic::QuicSocketAddress GetQuicSocketAddr(const InetSocketAddress &addr){ 118 | Ipv4Address ns3_ip_addr=addr.GetIpv4(); 119 | uint16_t port=addr.GetPort(); 120 | uint32_t ip_host_order=ns3_ip_addr.Get(); 121 | uint32_t ip_net_order=htonl(ip_host_order); 122 | in_addr addr_in; 123 | memcpy(&addr_in,&ip_net_order,sizeof(uint32_t)); 124 | quic::QuicIpAddress quic_ip_addr(addr_in); 125 | return quic::QuicSocketAddress(quic_ip_addr,port); 126 | } 127 | 128 | InetSocketAddress GetNs3SocketAddr(const quic::QuicSocketAddress &addr){ 129 | quic::QuicIpAddress quic_ip_addr=addr.host(); 130 | uint16_t port=addr.port(); 131 | in_addr addr_in=quic_ip_addr.GetIPv4(); 132 | uint32_t ip_net_order=0; 133 | memcpy(&ip_net_order,&addr_in,sizeof(uint32_t)); 134 | uint32_t ip_host_order=ntohl(ip_net_order); 135 | Ipv4Address ns3_ip_addr(ip_host_order); 136 | return InetSocketAddress{ns3_ip_addr,port}; 137 | } 138 | 139 | void set_quic_log_level(quiche::QuicLogLevel level){ 140 | if(!quic_log_level_setted){ 141 | auto sink = std::make_shared(); 142 | quiche::GetLogger().sinks().push_back(sink); 143 | quiche::GetLogger().set_level(quiche::ERROR); 144 | quic_log_level_setted=true; 145 | } 146 | } 147 | 148 | void set_quic_log_error_level(){ 149 | set_quic_log_level(quiche::ERROR); 150 | } 151 | 152 | bool set_quic_key_value(const std::string &key,const std::string &value){ 153 | bool success=false; 154 | auto flag_ptr = quiche::FlagRegistry::GetInstance().FindFlag(key); 155 | if(flag_ptr){ 156 | flag_ptr->SetValueFromString(value); 157 | success=true; 158 | } 159 | return success; 160 | } 161 | 162 | bool set_quic_cert_key(const std::string& quic_cert_path){ 163 | std::string certificate_file("certificate_file"); 164 | std::string certificate_file_path=quic_cert_path+std::string("leaf_cert.pem"); 165 | std::string key_file("key_file"); 166 | std::string key_file_path=quic_cert_path+std::string("leaf_cert.pkcs8"); 167 | bool success1=false,success2=false; 168 | success1=(access(certificate_file_path.c_str(), F_OK ) != -1); 169 | QUIC_LOG_IF(ERROR,!success1)<> 24) & 0xff; 187 | buffer[1] = (ip_host_order>> 16) & 0xff; 188 | buffer[2] = (ip_host_order>> 8) & 0xff; 189 | buffer[3] = (ip_host_order>> 0) & 0xff; 190 | std::string ret; 191 | ret=std::to_string((int)buffer[0])+period+ 192 | std::to_string((int)buffer[1])+period+ 193 | std::to_string((int)buffer[2])+period+ 194 | std::to_string((int)buffer[3]); 195 | return ret; 196 | } 197 | 198 | std::string Ns3QuicAddressPair2String(const Ns3QuicAddressPair& addr_pair){ 199 | std::string ret; 200 | std::string client_ip=GetIp2String(addr_pair.client_ip); 201 | std::string server_ip=GetIp2String(addr_pair.server_ip); 202 | std::string client_port=std::to_string(addr_pair.client_port); 203 | std::string server_port=std::to_string(addr_pair.server_port); 204 | ret=client_ip+colon+client_port+undeline+ 205 | server_ip+colon+server_port; 206 | return ret; 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /quic/model/ns3-quic-util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "ns3/ns3-quic-addr-pair.h" 4 | namespace ns3{ 5 | void set_quic_log_error_level(); 6 | bool set_quic_key_value(const std::string &key,const std::string &value); 7 | bool set_quic_cert_key(const std::string& quic_cert_path); 8 | std::string GetNs3Ipv4Address2String(const Ipv4Address& ip); 9 | std::string GetIp2String(uint32_t ip_host_order); 10 | std::string Ns3QuicAddressPair2String(const Ns3QuicAddressPair& addr_pair); 11 | bool MakePath(const std::string& path); 12 | int WallTimeMillis(); 13 | } 14 | -------------------------------------------------------------------------------- /quic/model/ns3-transport-stream.cc: -------------------------------------------------------------------------------- 1 | #include "ns3-transport-stream.h" 2 | #include 3 | 4 | #include "gquiche/quic/core/quic_buffer_allocator.h" 5 | #include "gquiche/quic/core/quic_error_codes.h" 6 | #include "gquiche/quic/core/quic_types.h" 7 | #include "gquiche/quic/core/quic_utils.h" 8 | #include "gquiche/quic/platform/api/quic_bug_tracker.h" 9 | #include "gquiche/quic/platform/api/quic_logging.h" 10 | namespace quic { 11 | 12 | Ns3TransportStream::Ns3TransportStream( 13 | QuicStreamId id, 14 | QuicSession* session) 15 | : QuicStream(id, 16 | session, 17 | /*is_static=*/false, 18 | QuicUtils::GetStreamType(id, 19 | session->connection()->perspective(), 20 | session->IsIncomingStream(id), 21 | session->version())){} 22 | Ns3TransportStream::~Ns3TransportStream(){ 23 | if(visitor_){ 24 | visitor_->OnDestroy(); 25 | } 26 | } 27 | size_t Ns3TransportStream::Read(char* buffer, size_t buffer_size,bool &fin) { 28 | iovec iov; 29 | iov.iov_base = buffer; 30 | iov.iov_len = buffer_size; 31 | const size_t result = sequencer()->Readv(&iov, 1); 32 | if (sequencer()->IsClosed()) { 33 | OnFinRead(); 34 | fin=true; 35 | } 36 | return result; 37 | } 38 | 39 | size_t Ns3TransportStream::Read(std::string* output,bool &fin) { 40 | const size_t old_size = output->size(); 41 | const size_t bytes_to_read = ReadableBytes(); 42 | output->resize(old_size + bytes_to_read); 43 | size_t bytes_read = Read(&(*output)[old_size], bytes_to_read,fin); 44 | QUICHE_DCHECK_EQ(bytes_to_read, bytes_read); 45 | output->resize(old_size + bytes_read); 46 | return bytes_read; 47 | } 48 | 49 | bool Ns3TransportStream::Write(absl::string_view data) { 50 | if (!CanWrite()) { 51 | return false; 52 | } 53 | 54 | QuicUniqueBufferPtr buffer = MakeUniqueBuffer( 55 | session()->connection()->helper()->GetStreamSendBufferAllocator(), 56 | data.size()); 57 | memcpy(buffer.get(), data.data(), data.size()); 58 | QuicMemSlice memslice(std::move(buffer), data.size()); 59 | QuicConsumedData consumed = 60 | WriteMemSlices(QuicMemSliceSpan(&memslice), /*fin=*/false); 61 | 62 | 63 | if (consumed.bytes_consumed == data.size()) { 64 | return true; 65 | } 66 | if (consumed.bytes_consumed == 0) { 67 | return false; 68 | } 69 | QUIC_BUG(Ns3TransportStream)<< "WriteMemSlices() unexpectedly partially consumed the input " 70 | "data, provided: " 71 | << data.size() << ", written: " << consumed.bytes_consumed; 72 | OnUnrecoverableError( 73 | QUIC_INTERNAL_ERROR, 74 | "WriteMemSlices() unexpectedly partially consumed the input data"); 75 | return false; 76 | } 77 | bool Ns3TransportStream::Write(const char*data,size_t size,bool fin){ 78 | if(!data&&fin){ 79 | return SendFin(); 80 | } 81 | if (!CanWrite()) { 82 | return false; 83 | } 84 | 85 | QuicUniqueBufferPtr buffer = MakeUniqueBuffer( 86 | session()->connection()->helper()->GetStreamSendBufferAllocator(), 87 | size); 88 | memcpy(buffer.get(), data, size); 89 | QuicMemSlice memslice(std::move(buffer),size); 90 | QuicConsumedData consumed = 91 | WriteMemSlices(QuicMemSliceSpan(&memslice),fin); 92 | 93 | if (consumed.bytes_consumed ==size) { 94 | return true; 95 | } 96 | if (consumed.bytes_consumed == 0) { 97 | return false; 98 | } 99 | QUIC_BUG(Ns3TransportStream)<< "WriteMemSlices() unexpectedly partially consumed the input " 100 | "data, provided: " 101 | << size << ", written: " << consumed.bytes_consumed; 102 | OnUnrecoverableError( 103 | QUIC_INTERNAL_ERROR, 104 | "WriteMemSlices() unexpectedly partially consumed the input data"); 105 | return false; 106 | } 107 | bool Ns3TransportStream::SendFin() { 108 | if (!CanWrite()) { 109 | return false; 110 | } 111 | 112 | QuicMemSlice empty; 113 | QuicConsumedData consumed = 114 | WriteMemSlices(QuicMemSliceSpan(&empty), /*fin=*/true); 115 | QUICHE_DCHECK_EQ(consumed.bytes_consumed, 0u); 116 | return consumed.fin_consumed; 117 | } 118 | 119 | bool Ns3TransportStream::CanWrite() const { 120 | return CanWriteNewData() &&!write_side_closed(); 121 | } 122 | 123 | size_t Ns3TransportStream::ReadableBytes() const { 124 | return sequencer()->ReadableBytes(); 125 | } 126 | 127 | void Ns3TransportStream::OnDataAvailable() { 128 | if (sequencer()->IsClosed()) { 129 | OnFinRead(); 130 | return; 131 | } 132 | 133 | if (visitor_ == nullptr) { 134 | return; 135 | } 136 | if (ReadableBytes() == 0) { 137 | return; 138 | } 139 | visitor_->OnCanRead(); 140 | } 141 | 142 | void Ns3TransportStream::OnCanWriteNewData() { 143 | // Ensure the origin check has been completed, as the stream can be notified 144 | // about being writable before that. 145 | if (!CanWrite()) { 146 | return; 147 | } 148 | if (visitor_ != nullptr) { 149 | visitor_->OnCanWrite(); 150 | } 151 | } 152 | } // namespace quic 153 | -------------------------------------------------------------------------------- /quic/model/ns3-transport-stream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "absl/strings/string_view.h" 7 | #include "gquiche/quic/core/quic_session.h" 8 | #include "gquiche/quic/core/quic_stream.h" 9 | #include "gquiche/quic/core/quic_types.h" 10 | 11 | namespace quic{ 12 | class Ns3TransportStream : public QuicStream { 13 | public: 14 | class Visitor { 15 | public: 16 | virtual ~Visitor() {} 17 | virtual void OnCanRead() = 0; 18 | virtual void OnCanWrite() = 0; 19 | virtual void OnDestroy()=0; 20 | }; 21 | 22 | Ns3TransportStream(QuicStreamId id, 23 | QuicSession* session); 24 | ~Ns3TransportStream(); 25 | // Reads at most |buffer_size| bytes into |buffer| and returns the number of 26 | // bytes actually read. 27 | size_t Read(char* buffer, size_t buffer_size,bool &fin); 28 | // Reads all available data and appends it to the end of |output|. 29 | size_t Read(std::string* output,bool &fin); 30 | // Writes |data| into the stream. Returns true on success. 31 | ABSL_MUST_USE_RESULT bool Write(absl::string_view data); 32 | ABSL_MUST_USE_RESULT bool Write(const char*data,size_t size,bool fin); 33 | // Sends the FIN on the stream. Returns true on success. 34 | ABSL_MUST_USE_RESULT bool SendFin(); 35 | 36 | // Indicates whether it is possible to write into stream right now. 37 | bool CanWrite() const; 38 | // Indicates the number of bytes that can be read from the stream. 39 | size_t ReadableBytes() const; 40 | 41 | // QuicSession method implementations. 42 | void OnDataAvailable() override; 43 | void OnCanWriteNewData() override; 44 | void set_visitor(std::unique_ptr visitor) { 45 | visitor_ =std::move(visitor); 46 | } 47 | protected: 48 | std::unique_ptr visitor_ = nullptr; 49 | bool fin_read_notified_ = false; 50 | }; 51 | } 52 | 53 | -------------------------------------------------------------------------------- /quic/model/quic-test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "gquiche/quic/core/quic_constants.h" 4 | #include "gquiche/quic/platform/api/quic_default_proof_providers.h" 5 | #include "gquiche/quic/platform/api/quic_logging.h" 6 | #include "gquiche/quic/core/quic_one_block_arena.h" 7 | 8 | #include "ns3-quic-clock.h" 9 | #include "ns3/quic-test.h" 10 | 11 | #include "ns3/simulator.h" 12 | #include "ns3/assert.h" 13 | #include "ns3/ns3-quic-util.h" 14 | #include "ns3-quic-addr-convert.h" 15 | #include "ns3-quic-flags.h" 16 | namespace quic{ 17 | void set_test_value(const std::string &v){ 18 | std::string key("test_value"); 19 | ns3::set_quic_key_value(key,v); 20 | } 21 | void print_test_value(){ 22 | int32_t test_value=get_test_value(); 23 | std::cout< proof_source=quic::CreateDefaultProofSource(); 56 | if(!proof_source){ 57 | QUIC_LOG(ERROR)<<"quic_cert path is not right"< 3 | #include 4 | #include "ns3/object.h" 5 | #include "ns3/event-id.h" 6 | #include "ns3/nstime.h" 7 | namespace quic{ 8 | void set_test_value(const std::string &v); 9 | void print_test_value(); 10 | void print_address(); 11 | void parser_flags(const char* usage,int argc, const char* const* argv); 12 | void test_quic_log(); 13 | void test_proof_source(); 14 | } 15 | -------------------------------------------------------------------------------- /quic/wscript: -------------------------------------------------------------------------------- 1 | import os 2 | quiche_code_path = os.environ['QUICHE_SRC_DIR'] 3 | quiche_lib_path = os.path.join(quiche_code_path, 'build') 4 | quiche_build_inc_path=quiche_lib_path 5 | absl_inc_path= os.path.join(quiche_code_path, 'third_party', 'abseil-cpp') 6 | spdlog_inc_path=os.path.join(quiche_code_path, 'third_party', 'spdlog','include') 7 | boringssl_inc_path=os.path.join(quiche_code_path, 'third_party', 'boringssl','include') 8 | googleurl_inc_path=os.path.join(quiche_code_path, 'googleurl') 9 | def configure(conf): 10 | conf.env.append_value('INCLUDES',[absl_inc_path,absl_inc_path,spdlog_inc_path]) 11 | conf.env.append_value("CXXFLAGS",[ 12 | "-std=c++14", 13 | "-I" + quiche_code_path, 14 | "-I" + quiche_build_inc_path, 15 | "-I" +googleurl_inc_path, 16 | "-I" +absl_inc_path, 17 | "-I" +spdlog_inc_path, 18 | "-I" +boringssl_inc_path, 19 | "-Wno-unused-const-variable"]) 20 | conf.env.append_value("LINKFLAGS", [ 21 | "-L"+quiche_lib_path, 22 | ]) 23 | conf.env.append_value("LINKFLAGS", ["-lquiche_shared", "-lprotobuf"]) 24 | def build(bld): 25 | module= bld.create_ns3_module('quic') 26 | module.env.append_value("CXXFLAGS",[ 27 | "-D__STDC_CONSTANT_MACROS","-std=c++17"]) 28 | module.env.append_value("LIB", ["quiche_shared",'protobuf']) 29 | module.source = [ 30 | 'model/cc-algo/copa_sender.cc', 31 | 'model/cc-algo/vegas_sender.cc', 32 | 'model/ns3-client-network-helper.cc', 33 | 'model/ns3-packet-writer.cc', 34 | 'model/ns3-quic-alarm-engine.cc', 35 | 'model/ns3-quic-backend.cc', 36 | 'model/ns3-quic-channel.cc', 37 | 'model/ns3-quic-client.cc', 38 | 'model/ns3-quic-client-app.cc', 39 | 'model/ns3-quic-client-session.cc', 40 | 'model/ns3-quic-clock.cc', 41 | 'model/ns3-quic-congestion-factory.cc', 42 | 'model/ns3-quic-connection-helper.cc', 43 | 'model/ns3-quic-dispatcher.cc', 44 | 'model/ns3-quic-flags.cc', 45 | 'model/ns3-quic-server.cc', 46 | 'model/ns3-quic-server-app.cc', 47 | 'model/ns3-quic-server-session.cc', 48 | 'model/ns3-quic-session-base.cc', 49 | 'model/ns3-quic-tag.cc', 50 | 'model/ns3-quic-trace.cc', 51 | 'model/ns3-quic-util.cc', 52 | 'model/ns3-transport-stream.cc', 53 | 'model/quic-test.cc', 54 | ] 55 | headers = bld(features='ns3header') 56 | headers.module = 'quic' 57 | headers.source = [ 58 | 'model/ns3-quic-client-app.h', 59 | 'model/ns3-quic-congestion-factory.h', 60 | 'model/ns3-quic-server-app.h', 61 | 'model/ns3-quic-trace.h', 62 | 'model/ns3-quic-public.h', 63 | 'model/ns3-quic-addr-pair.h', 64 | 'model/ns3-quic-util.h', 65 | 'model/quic-test.h', 66 | ] 67 | module.env['INCLUDES'] += [ 68 | '.', 69 | 'model', 70 | 'model/cc-algo', 71 | ] 72 | -------------------------------------------------------------------------------- /results/1-bbr-inflight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoonyangZhang/quic-on-ns3/872a38a1c257a333c1fd68908f24b409f42e27ee/results/1-bbr-inflight.png -------------------------------------------------------------------------------- /results/1-bbr-owd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoonyangZhang/quic-on-ns3/872a38a1c257a333c1fd68908f24b409f42e27ee/results/1-bbr-owd.png -------------------------------------------------------------------------------- /results/1-bbr-send-rate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoonyangZhang/quic-on-ns3/872a38a1c257a333c1fd68908f24b409f42e27ee/results/1-bbr-send-rate.png -------------------------------------------------------------------------------- /results/1-copa-goodput.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoonyangZhang/quic-on-ns3/872a38a1c257a333c1fd68908f24b409f42e27ee/results/1-copa-goodput.png -------------------------------------------------------------------------------- /results/1-copa-inflight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoonyangZhang/quic-on-ns3/872a38a1c257a333c1fd68908f24b409f42e27ee/results/1-copa-inflight.png -------------------------------------------------------------------------------- /results/1-copa-owd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoonyangZhang/quic-on-ns3/872a38a1c257a333c1fd68908f24b409f42e27ee/results/1-copa-owd.png -------------------------------------------------------------------------------- /results/1-copa-send-rate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoonyangZhang/quic-on-ns3/872a38a1c257a333c1fd68908f24b409f42e27ee/results/1-copa-send-rate.png -------------------------------------------------------------------------------- /results/1-cubic-inflight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoonyangZhang/quic-on-ns3/872a38a1c257a333c1fd68908f24b409f42e27ee/results/1-cubic-inflight.png -------------------------------------------------------------------------------- /results/1-cubic-owd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoonyangZhang/quic-on-ns3/872a38a1c257a333c1fd68908f24b409f42e27ee/results/1-cubic-owd.png -------------------------------------------------------------------------------- /results/1-cubic-send-rate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoonyangZhang/quic-on-ns3/872a38a1c257a333c1fd68908f24b409f42e27ee/results/1-cubic-send-rate.png -------------------------------------------------------------------------------- /results/1-vegas-goodput.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoonyangZhang/quic-on-ns3/872a38a1c257a333c1fd68908f24b409f42e27ee/results/1-vegas-goodput.png -------------------------------------------------------------------------------- /results/1-vegas-inflight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoonyangZhang/quic-on-ns3/872a38a1c257a333c1fd68908f24b409f42e27ee/results/1-vegas-inflight.png -------------------------------------------------------------------------------- /results/1-vegas-owd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoonyangZhang/quic-on-ns3/872a38a1c257a333c1fd68908f24b409f42e27ee/results/1-vegas-owd.png -------------------------------------------------------------------------------- /results/1-vegas-send-rate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SoonyangZhang/quic-on-ns3/872a38a1c257a333c1fd68908f24b409f42e27ee/results/1-vegas-send-rate.png --------------------------------------------------------------------------------