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