Skip to content

Commit b669d96

Browse files
authored
Propagate events for path related activities (#623)
Motivation: There are multiple events that can happen that are related to network path (i.e. connection migration). We should allow the user to be notified for all of them Modifications: - Introduce QuicPathEvent and related subclasses which will be fired through the ChannelPipeline when a path related event happens Result: Be able to observe all events
1 parent a6af06e commit b669d96

File tree

6 files changed

+638
-4
lines changed

6 files changed

+638
-4
lines changed
Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
/*
2+
* Copyright 2023 The Netty Project
3+
*
4+
* The Netty Project licenses this file to you under the Apache License,
5+
* version 2.0 (the "License"); you may not use this file except in compliance
6+
* with the License. You may obtain a copy of the License at:
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
package io.netty.incubator.codec.quic;
17+
18+
import java.net.InetSocketAddress;
19+
import java.util.Objects;
20+
21+
import static java.util.Objects.requireNonNull;
22+
23+
/**
24+
* A network path specific {@link QuicEvent}.
25+
*/
26+
public abstract class QuicPathEvent implements QuicEvent {
27+
28+
private final InetSocketAddress local;
29+
private final InetSocketAddress remote;
30+
31+
QuicPathEvent(InetSocketAddress local, InetSocketAddress remote) {
32+
this.local = requireNonNull(local, "local");
33+
this.remote = requireNonNull(remote, "remote");
34+
}
35+
36+
/**
37+
* The local address of the network path.
38+
*
39+
* @return local
40+
*/
41+
public InetSocketAddress local() {
42+
return local;
43+
}
44+
45+
/**
46+
* The remote address of the network path.
47+
*
48+
* @return local
49+
*/
50+
public InetSocketAddress remote() {
51+
return remote;
52+
}
53+
54+
@Override
55+
public String toString() {
56+
return "QuicPathEvent{" +
57+
"local=" + local +
58+
", remote=" + remote +
59+
'}';
60+
}
61+
62+
@Override
63+
public boolean equals(Object o) {
64+
if (this == o) {
65+
return true;
66+
}
67+
if (o == null || getClass() != o.getClass()) {
68+
return false;
69+
}
70+
71+
QuicPathEvent that = (QuicPathEvent) o;
72+
if (!Objects.equals(local, that.local)) {
73+
return false;
74+
}
75+
return Objects.equals(remote, that.remote);
76+
}
77+
78+
@Override
79+
public int hashCode() {
80+
int result = local != null ? local.hashCode() : 0;
81+
result = 31 * result + (remote != null ? remote.hashCode() : 0);
82+
return result;
83+
}
84+
85+
public static final class New extends QuicPathEvent {
86+
/**
87+
* A new network path (local address, remote address) has been seen on a received packet.
88+
* Note that this event is only triggered for servers, as the client is responsible from initiating new paths.
89+
* The application may then probe this new path, if desired.
90+
*
91+
* @param local local address.
92+
* @param remote remote address.
93+
*/
94+
public New(InetSocketAddress local, InetSocketAddress remote) {
95+
super(local, remote);
96+
}
97+
98+
@Override
99+
public String toString() {
100+
return "QuicPathEvent.New{" +
101+
"local=" + local() +
102+
", remote=" + remote() +
103+
'}';
104+
}
105+
}
106+
107+
public static final class Validated extends QuicPathEvent {
108+
/**
109+
* The related network path between local and remote has been validated.
110+
*
111+
* @param local local address.
112+
* @param remote remote address.
113+
*/
114+
public Validated(InetSocketAddress local, InetSocketAddress remote) {
115+
super(local, remote);
116+
}
117+
118+
@Override
119+
public String toString() {
120+
return "QuicPathEvent.Validated{" +
121+
"local=" + local() +
122+
", remote=" + remote() +
123+
'}';
124+
}
125+
}
126+
127+
public static final class FailedValidation extends QuicPathEvent {
128+
/**
129+
* The related network path between local and remote failed to be validated.
130+
* This network path will not be used anymore, unless the application requests probing this path again.
131+
*
132+
* @param local local address.
133+
* @param remote remote address.
134+
*/
135+
public FailedValidation(InetSocketAddress local, InetSocketAddress remote) {
136+
super(local, remote);
137+
}
138+
139+
@Override
140+
public String toString() {
141+
return "QuicPathEvent.FailedValidation{" +
142+
"local=" + local() +
143+
", remote=" + remote() +
144+
'}';
145+
}
146+
}
147+
148+
public static final class Closed extends QuicPathEvent {
149+
150+
/**
151+
* The related network path between local and remote has been closed and is now unusable on this connection.
152+
*
153+
* @param local local address.
154+
* @param remote remote address.
155+
*/
156+
public Closed(InetSocketAddress local, InetSocketAddress remote) {
157+
super(local, remote);
158+
}
159+
160+
@Override
161+
public boolean equals(Object o) {
162+
if (this == o) {
163+
return true;
164+
}
165+
if (o == null || getClass() != o.getClass()) {
166+
return false;
167+
}
168+
return super.equals(o);
169+
}
170+
171+
@Override
172+
public String toString() {
173+
return "QuicPathEvent.Closed{" +
174+
"local=" + local() +
175+
", remote=" + remote() +
176+
'}';
177+
}
178+
}
179+
180+
public static final class ReusedSourceConnectionId extends QuicPathEvent {
181+
private final long seq;
182+
private final InetSocketAddress oldLocal;
183+
private final InetSocketAddress oldRemote;
184+
185+
/**
186+
* The stack observes that the Source Connection ID with the given sequence number,
187+
* initially used by the peer over the first pair of addresses, is now reused over
188+
* the second pair of addresses.
189+
*
190+
* @param seq sequence number
191+
* @param oldLocal old local address.
192+
* @param oldRemote old remote address.
193+
* @param local local address.
194+
* @param remote remote address.
195+
*/
196+
public ReusedSourceConnectionId(long seq, InetSocketAddress oldLocal, InetSocketAddress oldRemote,
197+
InetSocketAddress local, InetSocketAddress remote) {
198+
super(local, remote);
199+
this.seq = seq;
200+
this.oldLocal = requireNonNull(oldLocal, "oldLocal");
201+
this.oldRemote = requireNonNull(oldRemote, "oldRemote");
202+
}
203+
204+
/**
205+
* Source connection id sequence number.
206+
*
207+
* @return sequence number
208+
*/
209+
public long seq() {
210+
return seq;
211+
}
212+
213+
/**
214+
* The old local address of the network path.
215+
*
216+
* @return local
217+
*/
218+
public InetSocketAddress oldLocal() {
219+
return oldLocal;
220+
}
221+
222+
/**
223+
* The old remote address of the network path.
224+
*
225+
* @return local
226+
*/
227+
public InetSocketAddress oldRemote() {
228+
return oldRemote;
229+
}
230+
231+
@Override
232+
public boolean equals(Object o) {
233+
if (this == o) {
234+
return true;
235+
}
236+
if (o == null || getClass() != o.getClass()) {
237+
return false;
238+
}
239+
if (!super.equals(o)) {
240+
return false;
241+
}
242+
243+
ReusedSourceConnectionId that = (ReusedSourceConnectionId) o;
244+
245+
if (seq != that.seq) {
246+
return false;
247+
}
248+
if (!Objects.equals(oldLocal, that.oldLocal)) {
249+
return false;
250+
}
251+
return Objects.equals(oldRemote, that.oldRemote);
252+
}
253+
254+
@Override
255+
public int hashCode() {
256+
int result = super.hashCode();
257+
result = 31 * result + (int) (seq ^ (seq >>> 32));
258+
result = 31 * result + (oldLocal != null ? oldLocal.hashCode() : 0);
259+
result = 31 * result + (oldRemote != null ? oldRemote.hashCode() : 0);
260+
return result;
261+
}
262+
263+
@Override
264+
public String toString() {
265+
return "QuicPathEvent.ReusedSourceConnectionId{" +
266+
"seq=" + seq +
267+
", oldLocal=" + oldLocal +
268+
", oldRemote=" + oldRemote +
269+
", local=" + local() +
270+
", remote=" + remote() +
271+
'}';
272+
}
273+
}
274+
275+
public static final class PeerMigrated extends QuicPathEvent {
276+
277+
/**
278+
* The connection observed that the remote migrated over the network path denoted by the pair of addresses,
279+
* i.e., non-probing packets have been received on this network path. This is a server side only event.
280+
* Note that this event is only raised if the path has been validated.
281+
*
282+
* @param local local address.
283+
* @param remote remote address.
284+
*/
285+
public PeerMigrated(InetSocketAddress local, InetSocketAddress remote) {
286+
super(local, remote);
287+
}
288+
289+
@Override
290+
public String toString() {
291+
return "QuicPathEvent.PeerMigrated{" +
292+
"local=" + local() +
293+
", remote=" + remote() +
294+
'}';
295+
}
296+
}
297+
}

codec-classes-quic/src/main/java/io/netty/incubator/codec/quic/Quiche.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,14 @@ private static void loadNativeLibrary() {
290290
*/
291291
static final int QUICHE_CC_BBR = QuicheNativeStaticallyReferencedJniMethods.quiche_cc_bbr();
292292

293+
294+
static final int QUICHE_PATH_EVENT_NEW = QuicheNativeStaticallyReferencedJniMethods.quiche_path_event_new();
295+
static final int QUICHE_PATH_EVENT_VALIDATED = QuicheNativeStaticallyReferencedJniMethods.quiche_path_event_validated();
296+
static final int QUICHE_PATH_EVENT_FAILED_VALIDATION = QuicheNativeStaticallyReferencedJniMethods.quiche_path_event_failed_validation();
297+
static final int QUICHE_PATH_EVENT_CLOSED = QuicheNativeStaticallyReferencedJniMethods.quiche_path_event_closed();
298+
static final int QUICHE_PATH_EVENT_REUSED_SOURCE_CONNECTION_ID = QuicheNativeStaticallyReferencedJniMethods.quiche_path_event_reused_source_connection_id();
299+
static final int QUICHE_PATH_EVENT_PEER_MIGRATED = QuicheNativeStaticallyReferencedJniMethods.quiche_path_event_peer_migrated();
300+
293301
/**
294302
* See <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L105">quiche_version</a>.
295303
*/
@@ -553,6 +561,16 @@ static native int quiche_conn_stream_priority(
553561

554562
static native byte[] quiche_conn_retired_scid_next(long connAddr);
555563

564+
static native long quiche_conn_path_event_next(long connAddr);
565+
static native int quiche_path_event_type(long pathEvent);
566+
static native void quiche_path_event_free(long pathEvent);
567+
static native Object[] quiche_path_event_new(long pathEvent);
568+
static native Object[] quiche_path_event_validated(long pathEvent);
569+
static native Object[] quiche_path_event_failed_validation(long pathEvent);
570+
static native Object[] quiche_path_event_closed(long pathEvent);
571+
static native Object[] quiche_path_event_reused_source_connection_id(long pathEvent);
572+
static native Object[] quiche_path_event_peer_migrated(long pathEvent);
573+
556574
/**
557575
* See
558576
* <a href="https://github.com/cloudflare/quiche/blob/0.6.0/include/quiche.h#L115">quiche_config_new</a>.

codec-classes-quic/src/main/java/io/netty/incubator/codec/quic/QuicheNativeStaticallyReferencedJniMethods.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,5 +85,12 @@ final class QuicheNativeStaticallyReferencedJniMethods {
8585
static native int sizeofTimeT();
8686
static native int sizeofLong();
8787

88+
static native int quiche_path_event_new();
89+
static native int quiche_path_event_validated();
90+
static native int quiche_path_event_failed_validation();
91+
static native int quiche_path_event_closed();
92+
static native int quiche_path_event_reused_source_connection_id();
93+
static native int quiche_path_event_peer_migrated();
94+
8895
private QuicheNativeStaticallyReferencedJniMethods() { }
8996
}

0 commit comments

Comments
 (0)