1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.bootstrap;
17
18 import io.netty.channel.Channel;
19 import io.netty.channel.ChannelFuture;
20 import io.netty.channel.ChannelFutureListener;
21 import io.netty.channel.ChannelPipeline;
22 import io.netty.channel.ChannelPromise;
23 import io.netty.channel.EventLoop;
24 import io.netty.channel.EventLoopGroup;
25 import io.netty.resolver.AddressResolver;
26 import io.netty.resolver.AddressResolverGroup;
27 import io.netty.resolver.DefaultAddressResolverGroup;
28 import io.netty.resolver.NameResolver;
29 import io.netty.util.concurrent.Future;
30 import io.netty.util.concurrent.FutureListener;
31 import io.netty.util.internal.ObjectUtil;
32 import io.netty.util.internal.logging.InternalLogger;
33 import io.netty.util.internal.logging.InternalLoggerFactory;
34
35 import java.net.InetAddress;
36 import java.net.InetSocketAddress;
37 import java.net.SocketAddress;
38 import java.util.Collection;
39
40
41
42
43
44
45
46
47 public class Bootstrap extends AbstractBootstrap<Bootstrap, Channel> {
48
49 private static final InternalLogger logger = InternalLoggerFactory.getInstance(Bootstrap.class);
50
51 private final BootstrapConfig config = new BootstrapConfig(this);
52
53 private ExternalAddressResolver externalResolver;
54 private volatile boolean disableResolver;
55 private volatile SocketAddress remoteAddress;
56
57 public Bootstrap() { }
58
59 private Bootstrap(Bootstrap bootstrap) {
60 super(bootstrap);
61 externalResolver = bootstrap.externalResolver;
62 disableResolver = bootstrap.disableResolver;
63 remoteAddress = bootstrap.remoteAddress;
64 }
65
66
67
68
69
70
71
72
73
74 public Bootstrap resolver(AddressResolverGroup<?> resolver) {
75 externalResolver = resolver == null ? null : new ExternalAddressResolver(resolver);
76 disableResolver = false;
77 return this;
78 }
79
80
81
82
83
84 public Bootstrap disableResolver() {
85 externalResolver = null;
86 disableResolver = true;
87 return this;
88 }
89
90
91
92
93
94 public Bootstrap remoteAddress(SocketAddress remoteAddress) {
95 this.remoteAddress = remoteAddress;
96 return this;
97 }
98
99
100
101
102 public Bootstrap remoteAddress(String inetHost, int inetPort) {
103 remoteAddress = InetSocketAddress.createUnresolved(inetHost, inetPort);
104 return this;
105 }
106
107
108
109
110 public Bootstrap remoteAddress(InetAddress inetHost, int inetPort) {
111 remoteAddress = new InetSocketAddress(inetHost, inetPort);
112 return this;
113 }
114
115
116
117
118 public ChannelFuture connect() {
119 validate();
120 SocketAddress remoteAddress = this.remoteAddress;
121 if (remoteAddress == null) {
122 throw new IllegalStateException("remoteAddress not set");
123 }
124
125 return doResolveAndConnect(remoteAddress, config.localAddress());
126 }
127
128
129
130
131 public ChannelFuture connect(String inetHost, int inetPort) {
132 return connect(InetSocketAddress.createUnresolved(inetHost, inetPort));
133 }
134
135
136
137
138 public ChannelFuture connect(InetAddress inetHost, int inetPort) {
139 return connect(new InetSocketAddress(inetHost, inetPort));
140 }
141
142
143
144
145 public ChannelFuture connect(SocketAddress remoteAddress) {
146 ObjectUtil.checkNotNull(remoteAddress, "remoteAddress");
147 validate();
148 return doResolveAndConnect(remoteAddress, config.localAddress());
149 }
150
151
152
153
154 public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) {
155 ObjectUtil.checkNotNull(remoteAddress, "remoteAddress");
156 validate();
157 return doResolveAndConnect(remoteAddress, localAddress);
158 }
159
160
161
162
163 private ChannelFuture doResolveAndConnect(final SocketAddress remoteAddress, final SocketAddress localAddress) {
164 final ChannelFuture regFuture = initAndRegister();
165 final Channel channel = regFuture.channel();
166
167 if (regFuture.isDone()) {
168 if (!regFuture.isSuccess()) {
169 return regFuture;
170 }
171 return doResolveAndConnect0(channel, remoteAddress, localAddress, channel.newPromise());
172 } else {
173
174 final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
175 regFuture.addListener(future -> {
176
177
178 Throwable cause = future.cause();
179 if (cause != null) {
180
181
182 promise.setFailure(cause);
183 } else {
184
185
186 promise.registered();
187 doResolveAndConnect0(channel, remoteAddress, localAddress, promise);
188 }
189 });
190 return promise;
191 }
192 }
193
194 private ChannelFuture doResolveAndConnect0(final Channel channel, SocketAddress remoteAddress,
195 final SocketAddress localAddress, final ChannelPromise promise) {
196
197
198 promise.addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
199 if (promise.isDone()) {
200 return promise;
201 }
202
203 try {
204 if (disableResolver) {
205 doConnect(remoteAddress, localAddress, promise);
206 return promise;
207 }
208
209 final EventLoop eventLoop = channel.eventLoop();
210 AddressResolver<SocketAddress> resolver;
211 try {
212 resolver = ExternalAddressResolver.getOrDefault(externalResolver).getResolver(eventLoop);
213 } catch (Throwable cause) {
214 channel.close();
215 promise.tryFailure(cause);
216 return promise;
217 }
218
219 if (!resolver.isSupported(remoteAddress) || resolver.isResolved(remoteAddress)) {
220
221 doConnect(remoteAddress, localAddress, promise);
222 return promise;
223 }
224
225 final Future<SocketAddress> resolveFuture = resolver.resolve(remoteAddress);
226
227 if (resolveFuture.isDone()) {
228 final Throwable resolveFailureCause = resolveFuture.cause();
229
230 if (resolveFailureCause != null) {
231
232 channel.close();
233 promise.tryFailure(resolveFailureCause);
234 } else {
235
236 doConnect(resolveFuture.getNow(), localAddress, promise);
237 }
238 return promise;
239 }
240
241
242 resolveFuture.addListener((FutureListener<SocketAddress>) future -> {
243 Throwable cause = future.cause();
244 if (cause != null) {
245 channel.close();
246 promise.tryFailure(cause);
247 } else if (!promise.isDone()) {
248 doConnect(future.getNow(), localAddress, promise);
249 }
250 });
251 } catch (Throwable cause) {
252 promise.tryFailure(cause);
253 }
254 return promise;
255 }
256
257 private static void doConnect(
258 final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise connectPromise) {
259
260
261
262 final Channel channel = connectPromise.channel();
263 channel.eventLoop().execute(new Runnable() {
264 @Override
265 public void run() {
266 if (localAddress == null) {
267 channel.connect(remoteAddress, connectPromise);
268 } else {
269 channel.connect(remoteAddress, localAddress, connectPromise);
270 }
271 }
272 });
273 }
274
275 @Override
276 void init(Channel channel) throws Throwable {
277 ChannelPipeline p = channel.pipeline();
278 p.addLast(config.handler());
279
280 setChannelOptions(channel, newOptionsArray(), logger);
281
282 setAttributes(channel, newAttributesArray());
283 Collection<ChannelInitializerExtension> extensions = getInitializerExtensions();
284 if (!extensions.isEmpty()) {
285 for (ChannelInitializerExtension extension : extensions) {
286 try {
287 extension.postInitializeClientChannel(channel);
288 } catch (Exception e) {
289 logger.warn("Exception thrown from postInitializeClientChannel", e);
290 }
291 }
292 }
293 }
294
295 @Override
296 public Bootstrap validate() {
297 super.validate();
298 if (config.handler() == null) {
299 throw new IllegalStateException("handler not set");
300 }
301 return this;
302 }
303
304 @Override
305 @SuppressWarnings("CloneDoesntCallSuperClone")
306 public Bootstrap clone() {
307 return new Bootstrap(this);
308 }
309
310
311
312
313
314
315 public Bootstrap clone(EventLoopGroup group) {
316 Bootstrap bs = new Bootstrap(this);
317 bs.group = group;
318 return bs;
319 }
320
321 @Override
322 public final BootstrapConfig config() {
323 return config;
324 }
325
326 final SocketAddress remoteAddress() {
327 return remoteAddress;
328 }
329
330 final AddressResolverGroup<?> resolver() {
331 if (disableResolver) {
332 return null;
333 }
334 return ExternalAddressResolver.getOrDefault(externalResolver);
335 }
336
337
338
339 static final class ExternalAddressResolver {
340 final AddressResolverGroup<SocketAddress> resolverGroup;
341
342 @SuppressWarnings("unchecked")
343 ExternalAddressResolver(AddressResolverGroup<?> resolverGroup) {
344 this.resolverGroup = (AddressResolverGroup<SocketAddress>) resolverGroup;
345 }
346
347 @SuppressWarnings("unchecked")
348 static AddressResolverGroup<SocketAddress> getOrDefault(ExternalAddressResolver externalResolver) {
349 if (externalResolver == null) {
350 AddressResolverGroup<?> defaultResolverGroup = DefaultAddressResolverGroup.INSTANCE;
351 return (AddressResolverGroup<SocketAddress>) defaultResolverGroup;
352 }
353 return externalResolver.resolverGroup;
354 }
355 }
356 }