1
#pragma once
2

            
3
#include "envoy/event/dispatcher.h"
4

            
5
#include "source/common/network/utility.h"
6
#include "source/common/quic/envoy_quic_client_packet_writer_factory.h"
7
#include "source/common/quic/envoy_quic_network_observer_registry_factory.h"
8
#include "source/common/quic/envoy_quic_packet_writer.h"
9
#include "source/common/quic/envoy_quic_utils.h"
10
#include "source/common/quic/quic_network_connection.h"
11
#include "source/common/runtime/runtime_features.h"
12

            
13
#include "quiche/quic/core/http/quic_spdy_client_session.h"
14
#include "quiche/quic/core/quic_connection.h"
15

            
16
namespace Envoy {
17
namespace Quic {
18

            
19
// Limits the max number of sockets created.
20
constexpr uint8_t kMaxNumSocketSwitches = 5;
21

            
22
class PacketsToReadDelegate {
23
public:
24
3125
  virtual ~PacketsToReadDelegate() = default;
25

            
26
  virtual size_t numPacketsExpectedPerEventLoop() const PURE;
27
};
28

            
29
// A client QuicConnection instance managing its own file events.
30
class EnvoyQuicClientConnection : public quic::QuicConnection,
31
                                  public QuicNetworkConnection,
32
                                  public Network::UdpPacketProcessor {
33
public:
34
  // Holds all components needed for a QUIC connection probing/migration.
35
  class EnvoyQuicPathValidationContext : public quic::QuicPathValidationContext {
36
  public:
37
    EnvoyQuicPathValidationContext(const quic::QuicSocketAddress& self_address,
38
                                   const quic::QuicSocketAddress& peer_address,
39
                                   std::unique_ptr<EnvoyQuicPacketWriter> writer,
40
                                   std::unique_ptr<Network::ConnectionSocket> probing_socket);
41

            
42
    ~EnvoyQuicPathValidationContext() override;
43

            
44
    quic::QuicPacketWriter* WriterToUse() override;
45

            
46
    EnvoyQuicPacketWriter* releaseWriter();
47

            
48
    Network::ConnectionSocket& probingSocket();
49

            
50
    std::unique_ptr<Network::ConnectionSocket> releaseSocket();
51

            
52
  private:
53
    std::unique_ptr<EnvoyQuicPacketWriter> writer_;
54
    Network::ConnectionSocketPtr socket_;
55
  };
56

            
57
  class EnvoyQuicMigrationHelper : public quic::QuicMigrationHelper {
58
  public:
59
    EnvoyQuicMigrationHelper(EnvoyQuicClientConnection& connection,
60
                             OptRef<EnvoyQuicNetworkObserverRegistry> registry,
61
                             QuicClientPacketWriterFactory& writer_factory,
62
                             quic::QuicNetworkHandle initial_network)
63
2871
        : quic::QuicMigrationHelper(), connection_(connection), registry_(registry),
64
2871
          writer_factory_(writer_factory), initial_network_(initial_network) {}
65

            
66
    quic::QuicNetworkHandle FindAlternateNetwork(quic::QuicNetworkHandle network) override;
67

            
68
    std::unique_ptr<quic::QuicPathContextFactory> CreateQuicPathContextFactory() override;
69

            
70
    void OnMigrationToPathDone(std::unique_ptr<quic::QuicClientPathValidationContext> context,
71
                               bool success) override;
72

            
73
    quic::QuicNetworkHandle GetDefaultNetwork() override;
74

            
75
    quic::QuicNetworkHandle GetCurrentNetwork() override;
76

            
77
  private:
78
    EnvoyQuicClientConnection& connection_;
79
    OptRef<EnvoyQuicNetworkObserverRegistry> registry_;
80
    QuicClientPacketWriterFactory& writer_factory_;
81
    quic::QuicNetworkHandle initial_network_;
82
  };
83

            
84
  using EnvoyQuicMigrationHelperPtr = std::unique_ptr<EnvoyQuicMigrationHelper>;
85

            
86
  EnvoyQuicClientConnection(const quic::QuicConnectionId& server_connection_id,
87
                            quic::QuicConnectionHelperInterface& helper,
88
                            quic::QuicAlarmFactory& alarm_factory, quic::QuicPacketWriter* writer,
89
                            bool owns_writer,
90
                            const quic::ParsedQuicVersionVector& supported_versions,
91
                            Event::Dispatcher& dispatcher,
92
                            Network::ConnectionSocketPtr&& connection_socket,
93
                            quic::ConnectionIdGeneratorInterface& generator);
94

            
95
  // Network::UdpPacketProcessor
96
  void processPacket(Network::Address::InstanceConstSharedPtr local_address,
97
                     Network::Address::InstanceConstSharedPtr peer_address,
98
                     Buffer::InstancePtr buffer, MonotonicTime receive_time, uint8_t tos,
99
                     Buffer::OwnedImpl saved_cmsg) override;
100
  uint64_t maxDatagramSize() const override;
101
15
  void onDatagramsDropped(uint32_t) override {
102
    // TODO(mattklein123): Emit a stat for this.
103
15
  }
104
48942
  size_t numPacketsExpectedPerEventLoop() const override {
105
48942
    if (!Runtime::runtimeFeatureEnabled(
106
48942
            "envoy.reloadable_features.quic_upstream_reads_fixed_number_packets") &&
107
48942
        delegate_.has_value()) {
108
      return delegate_->numPacketsExpectedPerEventLoop();
109
    }
110
48942
    return DEFAULT_PACKETS_TO_READ_PER_CONNECTION;
111
48942
  }
112
432281
  const Network::IoHandle::UdpSaveCmsgConfig& saveCmsgConfig() const override {
113
432281
    static const Network::IoHandle::UdpSaveCmsgConfig empty_config{};
114
432281
    return empty_config;
115
432281
  };
116

            
117
  // Register file event and apply socket options.
118
  void setUpConnectionSocket(Network::ConnectionSocket& connection_socket,
119
                             OptRef<PacketsToReadDelegate> delegate);
120

            
121
  // Switch underlying socket with the given one. This is used in connection migration.
122
  void switchConnectionSocket(Network::ConnectionSocketPtr&& connection_socket);
123

            
124
  // quic::QuicConnection
125
  // Potentially trigger migration.
126
  void OnPathDegradingDetected() override;
127
  void OnCanWrite() override;
128

            
129
  // Called when port migration probing succeeds. Attempts to migrate this connection onto the new
130
  // socket extracted from context.
131
  void onPathValidationSuccess(std::unique_ptr<quic::QuicPathValidationContext> context);
132

            
133
  // Called when port migration probing fails. The probing socket from context will go out of scope
134
  // and be destructed.
135
  void onPathValidationFailure(std::unique_ptr<quic::QuicPathValidationContext> context);
136

            
137
  void setNumPtosForPortMigration(uint32_t num_ptos_for_path_degrading);
138

            
139
  // Probes the given peer address. If the probing succeeds, start sending packets to this address
140
  // instead.
141
  void
142
  probeAndMigrateToServerPreferredAddress(const quic::QuicSocketAddress& server_preferred_address);
143

            
144
  // Called if the associated QUIC session will handle migration.
145
  EnvoyQuicMigrationHelper&
146
  getOrCreateMigrationHelper(QuicClientPacketWriterFactory& writer_factory,
147
                             quic::QuicNetworkHandle initial_network,
148
                             OptRef<EnvoyQuicNetworkObserverRegistry> registry);
149

            
150
  // Called if this class will handle migration.
151
194
  void setWriterFactory(QuicClientPacketWriterFactory& writer_factory) {
152
194
    writer_factory_ = writer_factory;
153
194
  }
154

            
155
private:
156
  friend class EnvoyQuicClientConnectionPeer;
157

            
158
  // Receives notifications from the Quiche layer on path validation results.
159
  class EnvoyPathValidationResultDelegate : public quic::QuicPathValidator::ResultDelegate {
160
  public:
161
    explicit EnvoyPathValidationResultDelegate(EnvoyQuicClientConnection& connection);
162

            
163
    void OnPathValidationSuccess(std::unique_ptr<quic::QuicPathValidationContext> context,
164
                                 quic::QuicTime start_time) override;
165

            
166
    void OnPathValidationFailure(std::unique_ptr<quic::QuicPathValidationContext> context) override;
167

            
168
  private:
169
    EnvoyQuicClientConnection& connection_;
170
  };
171

            
172
  class EnvoyQuicClinetPathContextFactory : public quic::QuicPathContextFactory {
173
  public:
174
    EnvoyQuicClinetPathContextFactory(QuicClientPacketWriterFactory& writer_factory,
175
                                      EnvoyQuicClientConnection& connection)
176
2871
        : writer_factory_(writer_factory), connection_(connection) {}
177

            
178
    // quic::QuicPathContextFactory
179
    void CreatePathValidationContext(
180
        quic::QuicNetworkHandle network, quic::QuicSocketAddress peer_address,
181
        std::unique_ptr<quic::QuicPathContextFactory::CreationResultDelegate> result_delegate)
182
        override;
183

            
184
  private:
185
    QuicClientPacketWriterFactory& writer_factory_;
186
    EnvoyQuicClientConnection& connection_;
187
  };
188

            
189
  void onFileEvent(uint32_t events, Network::ConnectionSocket& connection_socket);
190

            
191
  void maybeMigratePort();
192

            
193
  void probeWithNewPort(const quic::QuicSocketAddress& peer_addr,
194
                        quic::PathValidationReason reason);
195

            
196
  OptRef<PacketsToReadDelegate> delegate_;
197
  uint32_t packets_dropped_{0};
198
  Event::Dispatcher& dispatcher_;
199
  bool migrate_port_on_path_degrading_{false};
200
  uint8_t num_socket_switches_{0};
201
  size_t num_packets_with_unknown_dst_address_{0};
202
  const bool disallow_mmsg_;
203
  // If set, the session will handle migration and this class will act as a migration helper.
204
  // Otherwise, writer_factory_ must be set. And this class will handle port migration upon path
205
  // degrading and migration to the server preferred address.
206
  EnvoyQuicMigrationHelperPtr migration_helper_;
207
  // TODO(danzh): Remove this once migration is fully handled by Quiche.
208
  OptRef<QuicClientPacketWriterFactory> writer_factory_;
209
};
210

            
211
} // namespace Quic
212
} // namespace Envoy