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(new ChannelFutureListener() {
176 @Override
177 public void operationComplete(ChannelFuture future) throws Exception {
178
179
180 Throwable cause = future.cause();
181 if (cause != null) {
182
183
184 promise.setFailure(cause);
185 } else {
186
187
188 promise.registered();
189 doResolveAndConnect0(channel, remoteAddress, localAddress, promise);
190 }
191 }
192 });
193 return promise;
194 }
195 }
196
197 private ChannelFuture doResolveAndConnect0(final Channel channel, SocketAddress remoteAddress,
198 final SocketAddress localAddress, final ChannelPromise promise) {
199
200
201 promise.addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
202 if (promise.isDone()) {
203 return promise;
204 }
205
206 try {
207 if (disableResolver) {
208 doConnect(remoteAddress, localAddress, promise);
209 return promise;
210 }
211
212 final EventLoop eventLoop = channel.eventLoop();
213 AddressResolver<SocketAddress> resolver;
214 try {
215 resolver = ExternalAddressResolver.getOrDefault(externalResolver).getResolver(eventLoop);
216 } catch (Throwable cause) {
217 channel.close();
218 promise.tryFailure(cause);
219 return promise;
220 }
221
222 if (!resolver.isSupported(remoteAddress) || resolver.isResolved(remoteAddress)) {
223
224 doConnect(remoteAddress, localAddress, promise);
225 return promise;
226 }
227
228 final Future<SocketAddress> resolveFuture = resolver.resolve(remoteAddress);
229
230 if (resolveFuture.isDone()) {
231 final Throwable resolveFailureCause = resolveFuture.cause();
232
233 if (resolveFailureCause != null) {
234
235 channel.close();
236 promise.tryFailure(resolveFailureCause);
237 } else {
238
239 doConnect(resolveFuture.getNow(), localAddress, promise);
240 }
241 return promise;
242 }
243
244
245 resolveFuture.addListener(new FutureListener<SocketAddress>() {
246 @Override
247 public void operationComplete(Future<SocketAddress> future) throws Exception {
248 Throwable cause = future.cause();
249 if (cause != null) {
250 channel.close();
251 promise.tryFailure(cause);
252 } else if (!promise.isDone()) {
253 doConnect(future.getNow(), localAddress, promise);
254 }
255 }
256 });
257 } catch (Throwable cause) {
258 promise.tryFailure(cause);
259 }
260 return promise;
261 }
262
263 private static void doConnect(
264 final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise connectPromise) {
265
266
267
268 final Channel channel = connectPromise.channel();
269 channel.eventLoop().execute(new Runnable() {
270 @Override
271 public void run() {
272 if (localAddress == null) {
273 channel.connect(remoteAddress, connectPromise);
274 } else {
275 channel.connect(remoteAddress, localAddress, connectPromise);
276 }
277 }
278 });
279 }
280
281 @Override
282 void init(Channel channel) throws Throwable {
283 ChannelPipeline p = channel.pipeline();
284 p.addLast(config.handler());
285
286 setChannelOptions(channel, newOptionsArray(), logger);
287
288 setAttributes(channel, newAttributesArray());
289 Collection<ChannelInitializerExtension> extensions = getInitializerExtensions();
290 if (!extensions.isEmpty()) {
291 for (ChannelInitializerExtension extension : extensions) {
292 try {
293 extension.postInitializeClientChannel(channel);
294 } catch (Exception e) {
295 logger.warn("Exception thrown from postInitializeClientChannel", e);
296 }
297 }
298 }
299 }
300
301 @Override
302 public Bootstrap validate() {
303 super.validate();
304 if (config.handler() == null) {
305 throw new IllegalStateException("handler not set");
306 }
307 return this;
308 }
309
310 @Override
311 @SuppressWarnings("CloneDoesntCallSuperClone")
312 public Bootstrap clone() {
313 return new Bootstrap(this);
314 }
315
316
317
318
319
320
321 public Bootstrap clone(EventLoopGroup group) {
322 Bootstrap bs = new Bootstrap(this);
323 bs.group = group;
324 return bs;
325 }
326
327 @Override
328 public final BootstrapConfig config() {
329 return config;
330 }
331
332 final SocketAddress remoteAddress() {
333 return remoteAddress;
334 }
335
336 final AddressResolverGroup<?> resolver() {
337 if (disableResolver) {
338 return null;
339 }
340 return ExternalAddressResolver.getOrDefault(externalResolver);
341 }
342
343
344
345 static final class ExternalAddressResolver {
346 final AddressResolverGroup<SocketAddress> resolverGroup;
347
348 @SuppressWarnings("unchecked")
349 ExternalAddressResolver(AddressResolverGroup<?> resolverGroup) {
350 this.resolverGroup = (AddressResolverGroup<SocketAddress>) resolverGroup;
351 }
352
353 @SuppressWarnings("unchecked")
354 static AddressResolverGroup<SocketAddress> getOrDefault(ExternalAddressResolver externalResolver) {
355 if (externalResolver == null) {
356 AddressResolverGroup<?> defaultResolverGroup = DefaultAddressResolverGroup.INSTANCE;
357 return (AddressResolverGroup<SocketAddress>) defaultResolverGroup;
358 }
359 return externalResolver.resolverGroup;
360 }
361 }
362 }