1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.quic;
17
18 import io.netty.channel.Channel;
19 import io.netty.channel.ChannelFuture;
20 import io.netty.channel.ChannelHandler;
21 import io.netty.channel.ChannelOption;
22 import io.netty.channel.EventLoop;
23 import io.netty.util.AttributeKey;
24 import io.netty.util.concurrent.Future;
25 import io.netty.util.concurrent.Promise;
26 import io.netty.util.internal.ObjectUtil;
27 import io.netty.util.internal.logging.InternalLogger;
28 import io.netty.util.internal.logging.InternalLoggerFactory;
29 import org.jetbrains.annotations.Nullable;
30
31 import java.net.InetSocketAddress;
32 import java.net.SocketAddress;
33 import java.util.HashMap;
34 import java.util.LinkedHashMap;
35 import java.util.Map;
36
37
38
39
40 public final class QuicChannelBootstrap {
41 private static final InternalLogger logger = InternalLoggerFactory.getInstance(QuicChannelBootstrap.class);
42
43 private final Channel parent;
44
45
46 private final Map<ChannelOption<?>, Object> options = new LinkedHashMap<>();
47 private final Map<AttributeKey<?>, Object> attrs = new HashMap<>();
48 private final Map<ChannelOption<?>, Object> streamOptions = new LinkedHashMap<>();
49 private final Map<AttributeKey<?>, Object> streamAttrs = new HashMap<>();
50
51 private SocketAddress local;
52 private SocketAddress remote;
53 private QuicConnectionAddress connectionAddress = QuicConnectionAddress.EPHEMERAL;
54 private ChannelHandler handler;
55 private ChannelHandler streamHandler;
56
57
58
59
60
61
62
63
64 QuicChannelBootstrap(Channel parent) {
65 Quic.ensureAvailability();
66 this.parent = ObjectUtil.checkNotNull(parent, "parent");
67 }
68
69
70
71
72
73
74
75
76
77
78 public <T> QuicChannelBootstrap option(ChannelOption<T> option, @Nullable T value) {
79 Quic.updateOptions(options, option, value);
80 return this;
81 }
82
83
84
85
86
87
88
89
90
91
92 public <T> QuicChannelBootstrap attr(AttributeKey<T> key, @Nullable T value) {
93 Quic.updateAttributes(attrs, key, value);
94 return this;
95 }
96
97
98
99
100
101
102
103
104
105 public QuicChannelBootstrap handler(ChannelHandler handler) {
106 this.handler = ObjectUtil.checkNotNull(handler, "handler");
107 return this;
108 }
109
110
111
112
113
114
115
116
117
118
119 public <T> QuicChannelBootstrap streamOption(ChannelOption<T> option, @Nullable T value) {
120 Quic.updateOptions(streamOptions, option, value);
121 return this;
122 }
123
124
125
126
127
128
129
130
131
132
133 public <T> QuicChannelBootstrap streamAttr(AttributeKey<T> key, @Nullable T value) {
134 Quic.updateAttributes(streamAttrs, key, value);
135 return this;
136 }
137
138
139
140
141
142
143
144
145
146 public QuicChannelBootstrap streamHandler(ChannelHandler streamHandler) {
147 this.streamHandler = ObjectUtil.checkNotNull(streamHandler, "streamHandler");
148 return this;
149 }
150
151
152
153
154
155
156
157 public QuicChannelBootstrap localAddress(SocketAddress local) {
158 this.local = ObjectUtil.checkNotNull(local, "local");
159 return this;
160 }
161
162
163
164
165
166
167
168 public QuicChannelBootstrap remoteAddress(SocketAddress remote) {
169 this.remote = ObjectUtil.checkNotNull(remote, "remote");
170 return this;
171 }
172
173
174
175
176
177
178
179
180 public QuicChannelBootstrap connectionAddress(QuicConnectionAddress connectionAddress) {
181 this.connectionAddress = ObjectUtil.checkNotNull(connectionAddress, "connectionAddress");
182 return this;
183 }
184
185
186
187
188
189
190 public Future<QuicChannel> connect() {
191 return connect(parent.eventLoop().newPromise());
192 }
193
194
195
196
197
198
199
200
201 public Future<QuicChannel> connect(Promise<QuicChannel> promise) {
202 if (handler == null && streamHandler == null) {
203 throw new IllegalStateException("handler and streamHandler not set");
204 }
205 SocketAddress local = this.local;
206 if (local == null) {
207 local = parent.localAddress();
208 }
209 if (local == null) {
210 local = new InetSocketAddress(0);
211 }
212
213 SocketAddress remote = this.remote;
214 if (remote == null) {
215 remote = parent.remoteAddress();
216 }
217 if (remote == null) {
218 throw new IllegalStateException("remote not set");
219 }
220
221 final QuicConnectionAddress address = connectionAddress;
222 QuicChannel channel = QuicheQuicChannel.forClient(parent, (InetSocketAddress) local,
223 (InetSocketAddress) remote,
224 streamHandler, Quic.toOptionsArray(streamOptions), Quic.toAttributesArray(streamAttrs));
225
226 Quic.setupChannel(channel, Quic.toOptionsArray(options), Quic.toAttributesArray(attrs), handler, logger);
227 EventLoop eventLoop = parent.eventLoop();
228 eventLoop.register(channel).addListener((ChannelFuture future) -> {
229 Throwable cause = future.cause();
230 if (cause != null) {
231 promise.setFailure(cause);
232 } else {
233 channel.connect(address).addListener(f -> {
234 Throwable error = f.cause();
235 if (error != null) {
236 promise.setFailure(error);
237 } else {
238 promise.setSuccess(channel);
239 }
240 });
241 }
242 });
243 return promise;
244 }
245 }