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) throws Throwable {
275 ChannelPipeline p = channel.pipeline();
276 p.addLast(config.handler());
277
278 setChannelOptions(channel, newOptionsArray(), logger);
279
280 setAttributes(channel, newAttributesArray());
281 Collection<ChannelInitializerExtension> extensions = getInitializerExtensions();
282 if (!extensions.isEmpty()) {
283 for (ChannelInitializerExtension extension : extensions) {
284 try {
285 extension.postInitializeClientChannel(channel);
286 } catch (Exception e) {
287 logger.warn("Exception thrown from postInitializeClientChannel", e);
288 }
289 }
290 }
291 }
292
293 @Override
294 public Bootstrap validate() {
295 super.validate();
296 if (config.handler() == null) {
297 throw new IllegalStateException("handler not set");
298 }
299 return this;
300 }
301
302 @Override
303 @SuppressWarnings("CloneDoesntCallSuperClone")
304 public Bootstrap clone() {
305 return new Bootstrap(this);
306 }
307
308
309
310
311
312
313 public Bootstrap clone(EventLoopGroup group) {
314 Bootstrap bs = new Bootstrap(this);
315 bs.group = group;
316 return bs;
317 }
318
319 @Override
320 public final BootstrapConfig config() {
321 return config;
322 }
323
324 final SocketAddress remoteAddress() {
325 return remoteAddress;
326 }
327
328 final AddressResolverGroup<?> resolver() {
329 if (disableResolver) {
330 return null;
331 }
332 return ExternalAddressResolver.getOrDefault(externalResolver);
333 }
334
335
336
337 static final class ExternalAddressResolver {
338 final AddressResolverGroup<SocketAddress> resolverGroup;
339
340 @SuppressWarnings("unchecked")
341 ExternalAddressResolver(AddressResolverGroup<?> resolverGroup) {
342 this.resolverGroup = (AddressResolverGroup<SocketAddress>) resolverGroup;
343 }
344
345 @SuppressWarnings("unchecked")
346 static AddressResolverGroup<SocketAddress> getOrDefault(ExternalAddressResolver externalResolver) {
347 if (externalResolver == null) {
348 AddressResolverGroup<?> defaultResolverGroup = DefaultAddressResolverGroup.INSTANCE;
349 return (AddressResolverGroup<SocketAddress>) defaultResolverGroup;
350 }
351 return externalResolver.resolverGroup;
352 }
353 }
354 }