• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2014 The gRPC Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package io.grpc.netty;
18 
19 import static com.google.common.base.Preconditions.checkArgument;
20 import static io.grpc.internal.GrpcUtil.DEFAULT_MAX_MESSAGE_SIZE;
21 import static io.grpc.internal.GrpcUtil.DEFAULT_SERVER_KEEPALIVE_TIMEOUT_NANOS;
22 import static io.grpc.internal.GrpcUtil.DEFAULT_SERVER_KEEPALIVE_TIME_NANOS;
23 import static io.grpc.internal.GrpcUtil.SERVER_KEEPALIVE_TIME_NANOS_DISABLED;
24 
25 import com.google.common.annotations.VisibleForTesting;
26 import com.google.common.base.Preconditions;
27 import com.google.errorprone.annotations.CanIgnoreReturnValue;
28 import io.grpc.ExperimentalApi;
29 import io.grpc.Internal;
30 import io.grpc.ServerStreamTracer;
31 import io.grpc.internal.AbstractServerImplBuilder;
32 import io.grpc.internal.GrpcUtil;
33 import io.grpc.internal.KeepAliveManager;
34 import io.grpc.internal.TransportTracer;
35 import io.netty.channel.ChannelOption;
36 import io.netty.channel.EventLoopGroup;
37 import io.netty.channel.ServerChannel;
38 import io.netty.channel.socket.nio.NioServerSocketChannel;
39 import io.netty.handler.ssl.SslContext;
40 import java.io.File;
41 import java.io.InputStream;
42 import java.net.InetSocketAddress;
43 import java.net.SocketAddress;
44 import java.util.HashMap;
45 import java.util.List;
46 import java.util.Map;
47 import java.util.concurrent.TimeUnit;
48 import javax.annotation.CheckReturnValue;
49 import javax.annotation.Nullable;
50 import javax.net.ssl.SSLException;
51 
52 /**
53  * A builder to help simplify the construction of a Netty-based GRPC server.
54  */
55 @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1784")
56 @CanIgnoreReturnValue
57 public final class NettyServerBuilder extends AbstractServerImplBuilder<NettyServerBuilder> {
58   public static final int DEFAULT_FLOW_CONTROL_WINDOW = 1048576; // 1MiB
59 
60   static final long MAX_CONNECTION_IDLE_NANOS_DISABLED = Long.MAX_VALUE;
61   static final long MAX_CONNECTION_AGE_NANOS_DISABLED = Long.MAX_VALUE;
62   static final long MAX_CONNECTION_AGE_GRACE_NANOS_INFINITE = Long.MAX_VALUE;
63 
64   private static final long MIN_KEEPALIVE_TIME_NANO = TimeUnit.MILLISECONDS.toNanos(1L);
65   private static final long MIN_KEEPALIVE_TIMEOUT_NANO = TimeUnit.MICROSECONDS.toNanos(499L);
66   private static final long MIN_MAX_CONNECTION_IDLE_NANO = TimeUnit.SECONDS.toNanos(1L);
67   private static final long MIN_MAX_CONNECTION_AGE_NANO = TimeUnit.SECONDS.toNanos(1L);
68   private static final long AS_LARGE_AS_INFINITE = TimeUnit.DAYS.toNanos(1000L);
69 
70   private final SocketAddress address;
71   private Class<? extends ServerChannel> channelType = NioServerSocketChannel.class;
72   private final Map<ChannelOption<?>, Object> channelOptions =
73       new HashMap<ChannelOption<?>, Object>();
74   @Nullable
75   private EventLoopGroup bossEventLoopGroup;
76   @Nullable
77   private EventLoopGroup workerEventLoopGroup;
78   private SslContext sslContext;
79   private ProtocolNegotiator protocolNegotiator;
80   private int maxConcurrentCallsPerConnection = Integer.MAX_VALUE;
81   private int flowControlWindow = DEFAULT_FLOW_CONTROL_WINDOW;
82   private int maxMessageSize = DEFAULT_MAX_MESSAGE_SIZE;
83   private int maxHeaderListSize = GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE;
84   private long keepAliveTimeInNanos =  DEFAULT_SERVER_KEEPALIVE_TIME_NANOS;
85   private long keepAliveTimeoutInNanos = DEFAULT_SERVER_KEEPALIVE_TIMEOUT_NANOS;
86   private long maxConnectionIdleInNanos = MAX_CONNECTION_IDLE_NANOS_DISABLED;
87   private long maxConnectionAgeInNanos = MAX_CONNECTION_AGE_NANOS_DISABLED;
88   private long maxConnectionAgeGraceInNanos = MAX_CONNECTION_AGE_GRACE_NANOS_INFINITE;
89   private boolean permitKeepAliveWithoutCalls;
90   private long permitKeepAliveTimeInNanos = TimeUnit.MINUTES.toNanos(5);
91 
92   /**
93    * Creates a server builder that will bind to the given port.
94    *
95    * @param port the port on which the server is to be bound.
96    * @return the server builder.
97    */
98   @CheckReturnValue
forPort(int port)99   public static NettyServerBuilder forPort(int port) {
100     return new NettyServerBuilder(port);
101   }
102 
103   /**
104    * Creates a server builder configured with the given {@link SocketAddress}.
105    *
106    * @param address the socket address on which the server is to be bound.
107    * @return the server builder
108    */
109   @CheckReturnValue
forAddress(SocketAddress address)110   public static NettyServerBuilder forAddress(SocketAddress address) {
111     return new NettyServerBuilder(address);
112   }
113 
114   @CheckReturnValue
NettyServerBuilder(int port)115   private NettyServerBuilder(int port) {
116     this.address = new InetSocketAddress(port);
117   }
118 
119   @CheckReturnValue
NettyServerBuilder(SocketAddress address)120   private NettyServerBuilder(SocketAddress address) {
121     this.address = address;
122   }
123 
124   /**
125    * Specify the channel type to use, by default we use {@link NioServerSocketChannel}.
126    */
channelType(Class<? extends ServerChannel> channelType)127   public NettyServerBuilder channelType(Class<? extends ServerChannel> channelType) {
128     this.channelType = Preconditions.checkNotNull(channelType, "channelType");
129     return this;
130   }
131 
132   /**
133    * Specifies a channel option. As the underlying channel as well as network implementation may
134    * ignore this value applications should consider it a hint.
135    *
136    * @since 1.9.0
137    */
withChildOption(ChannelOption<T> option, T value)138   public <T> NettyServerBuilder withChildOption(ChannelOption<T> option, T value) {
139     this.channelOptions.put(option, value);
140     return this;
141   }
142 
143   /**
144    * Provides the boss EventGroupLoop to the server.
145    *
146    * <p>It's an optional parameter. If the user has not provided one when the server is built, the
147    * builder will use the default one which is static.
148    *
149    * <p>The server won't take ownership of the given EventLoopGroup. It's caller's responsibility
150    * to shut it down when it's desired.
151    *
152    * <p>Grpc uses non-daemon {@link Thread}s by default and thus a {@link io.grpc.Server} will
153    * continue to run even after the main thread has terminated. However, users have to be cautious
154    * when providing their own {@link EventLoopGroup}s.
155    * For example, Netty's {@link EventLoopGroup}s use daemon threads by default
156    * and thus an application with only daemon threads running besides the main thread will exit as
157    * soon as the main thread completes.
158    * A simple solution to this problem is to call {@link io.grpc.Server#awaitTermination()} to
159    * keep the main thread alive until the server has terminated.
160    */
bossEventLoopGroup(EventLoopGroup group)161   public NettyServerBuilder bossEventLoopGroup(EventLoopGroup group) {
162     this.bossEventLoopGroup = group;
163     return this;
164   }
165 
166   /**
167    * Provides the worker EventGroupLoop to the server.
168    *
169    * <p>It's an optional parameter. If the user has not provided one when the server is built, the
170    * builder will create one.
171    *
172    * <p>The server won't take ownership of the given EventLoopGroup. It's caller's responsibility
173    * to shut it down when it's desired.
174    *
175    * <p>Grpc uses non-daemon {@link Thread}s by default and thus a {@link io.grpc.Server} will
176    * continue to run even after the main thread has terminated. However, users have to be cautious
177    * when providing their own {@link EventLoopGroup}s.
178    * For example, Netty's {@link EventLoopGroup}s use daemon threads by default
179    * and thus an application with only daemon threads running besides the main thread will exit as
180    * soon as the main thread completes.
181    * A simple solution to this problem is to call {@link io.grpc.Server#awaitTermination()} to
182    * keep the main thread alive until the server has terminated.
183    */
workerEventLoopGroup(EventLoopGroup group)184   public NettyServerBuilder workerEventLoopGroup(EventLoopGroup group) {
185     this.workerEventLoopGroup = group;
186     return this;
187   }
188 
189   /**
190    * Sets the TLS context to use for encryption. Providing a context enables encryption. It must
191    * have been configured with {@link GrpcSslContexts}, but options could have been overridden.
192    */
sslContext(SslContext sslContext)193   public NettyServerBuilder sslContext(SslContext sslContext) {
194     if (sslContext != null) {
195       checkArgument(sslContext.isServer(),
196           "Client SSL context can not be used for server");
197       GrpcSslContexts.ensureAlpnAndH2Enabled(sslContext.applicationProtocolNegotiator());
198     }
199     this.sslContext = sslContext;
200     return this;
201   }
202 
203   /**
204    * Sets the {@link ProtocolNegotiator} to be used. If non-{@code null}, overrides the value
205    * specified in {@link #sslContext(SslContext)}.
206    *
207    * <p>Default: {@code null}.
208    */
209   @Internal
protocolNegotiator( @ullable ProtocolNegotiator protocolNegotiator)210   public final NettyServerBuilder protocolNegotiator(
211           @Nullable ProtocolNegotiator protocolNegotiator) {
212     this.protocolNegotiator = protocolNegotiator;
213     return this;
214   }
215 
216   @Override
setTracingEnabled(boolean value)217   protected void setTracingEnabled(boolean value) {
218     super.setTracingEnabled(value);
219   }
220 
221   @Override
setStatsEnabled(boolean value)222   protected void setStatsEnabled(boolean value) {
223     super.setStatsEnabled(value);
224   }
225 
226   @Override
setStatsRecordStartedRpcs(boolean value)227   protected void setStatsRecordStartedRpcs(boolean value) {
228     super.setStatsRecordStartedRpcs(value);
229   }
230 
231   @VisibleForTesting
setTransportTracerFactory(TransportTracer.Factory transportTracerFactory)232   NettyServerBuilder setTransportTracerFactory(TransportTracer.Factory transportTracerFactory) {
233     this.transportTracerFactory = transportTracerFactory;
234     return this;
235   }
236 
237   /**
238    * The maximum number of concurrent calls permitted for each incoming connection. Defaults to no
239    * limit.
240    */
maxConcurrentCallsPerConnection(int maxCalls)241   public NettyServerBuilder maxConcurrentCallsPerConnection(int maxCalls) {
242     checkArgument(maxCalls > 0, "max must be positive: %s", maxCalls);
243     this.maxConcurrentCallsPerConnection = maxCalls;
244     return this;
245   }
246 
247   /**
248    * Sets the HTTP/2 flow control window. If not called, the default value
249    * is {@link #DEFAULT_FLOW_CONTROL_WINDOW}).
250    */
flowControlWindow(int flowControlWindow)251   public NettyServerBuilder flowControlWindow(int flowControlWindow) {
252     checkArgument(flowControlWindow > 0, "flowControlWindow must be positive");
253     this.flowControlWindow = flowControlWindow;
254     return this;
255   }
256 
257   /**
258    * Sets the maximum message size allowed to be received on the server. If not called,
259    * defaults to 4 MiB. The default provides protection to services who haven't considered the
260    * possibility of receiving large messages while trying to be large enough to not be hit in normal
261    * usage.
262    *
263    * @deprecated Call {@link #maxInboundMessageSize} instead. This method will be removed in a
264    *     future release.
265    */
266   @Deprecated
maxMessageSize(int maxMessageSize)267   public NettyServerBuilder maxMessageSize(int maxMessageSize) {
268     return maxInboundMessageSize(maxMessageSize);
269   }
270 
271   /** {@inheritDoc} */
272   @Override
maxInboundMessageSize(int bytes)273   public NettyServerBuilder maxInboundMessageSize(int bytes) {
274     checkArgument(bytes >= 0, "bytes must be >= 0");
275     this.maxMessageSize = bytes;
276     return this;
277   }
278 
279   /**
280    * Sets the maximum size of header list allowed to be received. This is cumulative size of the
281    * headers with some overhead, as defined for
282    * <a href="http://httpwg.org/specs/rfc7540.html#rfc.section.6.5.2">
283    * HTTP/2's SETTINGS_MAX_HEADER_LIST_SIZE</a>. The default is 8 KiB.
284    */
maxHeaderListSize(int maxHeaderListSize)285   public NettyServerBuilder maxHeaderListSize(int maxHeaderListSize) {
286     checkArgument(maxHeaderListSize > 0, "maxHeaderListSize must be > 0");
287     this.maxHeaderListSize = maxHeaderListSize;
288     return this;
289   }
290 
291   /**
292    * Sets a custom keepalive time, the delay time for sending next keepalive ping. An unreasonably
293    * small value might be increased, and {@code Long.MAX_VALUE} nano seconds or an unreasonably
294    * large value will disable keepalive.
295    *
296    * @since 1.3.0
297    */
keepAliveTime(long keepAliveTime, TimeUnit timeUnit)298   public NettyServerBuilder keepAliveTime(long keepAliveTime, TimeUnit timeUnit) {
299     checkArgument(keepAliveTime > 0L, "keepalive time must be positive");
300     keepAliveTimeInNanos = timeUnit.toNanos(keepAliveTime);
301     keepAliveTimeInNanos = KeepAliveManager.clampKeepAliveTimeInNanos(keepAliveTimeInNanos);
302     if (keepAliveTimeInNanos >= AS_LARGE_AS_INFINITE) {
303       // Bump keepalive time to infinite. This disables keep alive.
304       keepAliveTimeInNanos = SERVER_KEEPALIVE_TIME_NANOS_DISABLED;
305     }
306     if (keepAliveTimeInNanos < MIN_KEEPALIVE_TIME_NANO) {
307       // Bump keepalive time.
308       keepAliveTimeInNanos = MIN_KEEPALIVE_TIME_NANO;
309     }
310     return this;
311   }
312 
313   /**
314    * Sets a custom keepalive timeout, the timeout for keepalive ping requests. An unreasonably small
315    * value might be increased.
316    *
317    * @since 1.3.0
318    */
keepAliveTimeout(long keepAliveTimeout, TimeUnit timeUnit)319   public NettyServerBuilder keepAliveTimeout(long keepAliveTimeout, TimeUnit timeUnit) {
320     checkArgument(keepAliveTimeout > 0L, "keepalive timeout must be positive");
321     keepAliveTimeoutInNanos = timeUnit.toNanos(keepAliveTimeout);
322     keepAliveTimeoutInNanos =
323         KeepAliveManager.clampKeepAliveTimeoutInNanos(keepAliveTimeoutInNanos);
324     if (keepAliveTimeoutInNanos < MIN_KEEPALIVE_TIMEOUT_NANO) {
325       // Bump keepalive timeout.
326       keepAliveTimeoutInNanos = MIN_KEEPALIVE_TIMEOUT_NANO;
327     }
328     return this;
329   }
330 
331   /**
332    * Sets a custom max connection idle time, connection being idle for longer than which will be
333    * gracefully terminated. Idleness duration is defined since the most recent time the number of
334    * outstanding RPCs became zero or the connection establishment. An unreasonably small value might
335    * be increased. {@code Long.MAX_VALUE} nano seconds or an unreasonably large value will disable
336    * max connection idle.
337    *
338    * @since 1.4.0
339    */
maxConnectionIdle(long maxConnectionIdle, TimeUnit timeUnit)340   public NettyServerBuilder maxConnectionIdle(long maxConnectionIdle, TimeUnit timeUnit) {
341     checkArgument(maxConnectionIdle > 0L, "max connection idle must be positive");
342     maxConnectionIdleInNanos = timeUnit.toNanos(maxConnectionIdle);
343     if (maxConnectionIdleInNanos >= AS_LARGE_AS_INFINITE) {
344       maxConnectionIdleInNanos = MAX_CONNECTION_IDLE_NANOS_DISABLED;
345     }
346     if (maxConnectionIdleInNanos < MIN_MAX_CONNECTION_IDLE_NANO) {
347       maxConnectionIdleInNanos = MIN_MAX_CONNECTION_IDLE_NANO;
348     }
349     return this;
350   }
351 
352   /**
353    * Sets a custom max connection age, connection lasting longer than which will be gracefully
354    * terminated. An unreasonably small value might be increased.  A random jitter of +/-10% will be
355    * added to it. {@code Long.MAX_VALUE} nano seconds or an unreasonably large value will disable
356    * max connection age.
357    *
358    * @since 1.3.0
359    */
maxConnectionAge(long maxConnectionAge, TimeUnit timeUnit)360   public NettyServerBuilder maxConnectionAge(long maxConnectionAge, TimeUnit timeUnit) {
361     checkArgument(maxConnectionAge > 0L, "max connection age must be positive");
362     maxConnectionAgeInNanos = timeUnit.toNanos(maxConnectionAge);
363     if (maxConnectionAgeInNanos >= AS_LARGE_AS_INFINITE) {
364       maxConnectionAgeInNanos = MAX_CONNECTION_AGE_NANOS_DISABLED;
365     }
366     if (maxConnectionAgeInNanos < MIN_MAX_CONNECTION_AGE_NANO) {
367       maxConnectionAgeInNanos = MIN_MAX_CONNECTION_AGE_NANO;
368     }
369     return this;
370   }
371 
372   /**
373    * Sets a custom grace time for the graceful connection termination. Once the max connection age
374    * is reached, RPCs have the grace time to complete. RPCs that do not complete in time will be
375    * cancelled, allowing the connection to terminate. {@code Long.MAX_VALUE} nano seconds or an
376    * unreasonably large value are considered infinite.
377    *
378    * @see #maxConnectionAge(long, TimeUnit)
379    * @since 1.3.0
380    */
maxConnectionAgeGrace(long maxConnectionAgeGrace, TimeUnit timeUnit)381   public NettyServerBuilder maxConnectionAgeGrace(long maxConnectionAgeGrace, TimeUnit timeUnit) {
382     checkArgument(maxConnectionAgeGrace >= 0L, "max connection age grace must be non-negative");
383     maxConnectionAgeGraceInNanos = timeUnit.toNanos(maxConnectionAgeGrace);
384     if (maxConnectionAgeGraceInNanos >= AS_LARGE_AS_INFINITE) {
385       maxConnectionAgeGraceInNanos = MAX_CONNECTION_AGE_GRACE_NANOS_INFINITE;
386     }
387     return this;
388   }
389 
390   /**
391    * Specify the most aggressive keep-alive time clients are permitted to configure. The server will
392    * try to detect clients exceeding this rate and when detected will forcefully close the
393    * connection. The default is 5 minutes.
394    *
395    * <p>Even though a default is defined that allows some keep-alives, clients must not use
396    * keep-alive without approval from the service owner. Otherwise, they may experience failures in
397    * the future if the service becomes more restrictive. When unthrottled, keep-alives can cause a
398    * significant amount of traffic and CPU usage, so clients and servers should be conservative in
399    * what they use and accept.
400    *
401    * @see #permitKeepAliveWithoutCalls(boolean)
402    * @since 1.3.0
403    */
permitKeepAliveTime(long keepAliveTime, TimeUnit timeUnit)404   public NettyServerBuilder permitKeepAliveTime(long keepAliveTime, TimeUnit timeUnit) {
405     checkArgument(keepAliveTime >= 0, "permit keepalive time must be non-negative");
406     permitKeepAliveTimeInNanos = timeUnit.toNanos(keepAliveTime);
407     return this;
408   }
409 
410   /**
411    * Sets whether to allow clients to send keep-alive HTTP/2 PINGs even if there are no outstanding
412    * RPCs on the connection. Defaults to {@code false}.
413    *
414    * @see #permitKeepAliveTime(long, TimeUnit)
415    * @since 1.3.0
416    */
permitKeepAliveWithoutCalls(boolean permit)417   public NettyServerBuilder permitKeepAliveWithoutCalls(boolean permit) {
418     permitKeepAliveWithoutCalls = permit;
419     return this;
420   }
421 
422   @Override
423   @CheckReturnValue
buildTransportServer( List<ServerStreamTracer.Factory> streamTracerFactories)424   protected NettyServer buildTransportServer(
425       List<ServerStreamTracer.Factory> streamTracerFactories) {
426     ProtocolNegotiator negotiator = protocolNegotiator;
427     if (negotiator == null) {
428       negotiator = sslContext != null ? ProtocolNegotiators.serverTls(sslContext) :
429               ProtocolNegotiators.serverPlaintext();
430     }
431 
432     return new NettyServer(
433         address, channelType, channelOptions, bossEventLoopGroup, workerEventLoopGroup,
434         negotiator, streamTracerFactories, transportTracerFactory,
435         maxConcurrentCallsPerConnection, flowControlWindow,
436         maxMessageSize, maxHeaderListSize, keepAliveTimeInNanos, keepAliveTimeoutInNanos,
437         maxConnectionIdleInNanos,
438         maxConnectionAgeInNanos, maxConnectionAgeGraceInNanos,
439         permitKeepAliveWithoutCalls, permitKeepAliveTimeInNanos, channelz);
440   }
441 
442   @Override
useTransportSecurity(File certChain, File privateKey)443   public NettyServerBuilder useTransportSecurity(File certChain, File privateKey) {
444     try {
445       sslContext = GrpcSslContexts.forServer(certChain, privateKey).build();
446     } catch (SSLException e) {
447       // This should likely be some other, easier to catch exception.
448       throw new RuntimeException(e);
449     }
450     return this;
451   }
452 
453   @Override
useTransportSecurity(InputStream certChain, InputStream privateKey)454   public NettyServerBuilder useTransportSecurity(InputStream certChain, InputStream privateKey) {
455     try {
456       sslContext = GrpcSslContexts.forServer(certChain, privateKey).build();
457     } catch (SSLException e) {
458       // This should likely be some other, easier to catch exception.
459       throw new RuntimeException(e);
460     }
461     return this;
462   }
463 }
464