View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  
28  package org.apache.hc.core5.reactor;
29  
30  import java.net.SocketAddress;
31  import java.util.concurrent.TimeUnit;
32  
33  import org.apache.hc.core5.annotation.Contract;
34  import org.apache.hc.core5.annotation.ThreadingBehavior;
35  import org.apache.hc.core5.util.Args;
36  import org.apache.hc.core5.util.TimeValue;
37  import org.apache.hc.core5.util.Timeout;
38  
39  /**
40   * I/O reactor configuration parameters.
41   *
42   * @since 4.2
43   */
44  @Contract(threading = ThreadingBehavior.IMMUTABLE)
45  public final class IOReactorConfig {
46  
47      public static final IOReactorConfig DEFAULT = new Builder().build();
48  
49      private final TimeValue selectInterval;
50      private final int ioThreadCount;
51      private final Timeout  soTimeout;
52      private final boolean soReuseAddress;
53      private final TimeValue soLinger;
54      private final boolean soKeepAlive;
55      private final boolean tcpNoDelay;
56      private final int trafficClass;
57      private final int sndBufSize;
58      private final int rcvBufSize;
59      private final int backlogSize;
60      private final SocketAddress socksProxyAddress;
61      private final String socksProxyUsername;
62      private final String socksProxyPassword;
63  
64      IOReactorConfig(
65              final TimeValue selectInterval,
66              final int ioThreadCount,
67              final Timeout soTimeout,
68              final boolean soReuseAddress,
69              final TimeValue soLinger,
70              final boolean soKeepAlive,
71              final boolean tcpNoDelay,
72              final int trafficClass,
73              final int sndBufSize,
74              final int rcvBufSize,
75              final int backlogSize,
76              final SocketAddress socksProxyAddress,
77              final String socksProxyUsername,
78              final String socksProxyPassword) {
79          super();
80          this.selectInterval = selectInterval;
81          this.ioThreadCount = ioThreadCount;
82          this.soTimeout = soTimeout;
83          this.soReuseAddress = soReuseAddress;
84          this.soLinger = soLinger;
85          this.soKeepAlive = soKeepAlive;
86          this.tcpNoDelay = tcpNoDelay;
87          this.trafficClass = trafficClass;
88          this.sndBufSize = sndBufSize;
89          this.rcvBufSize = rcvBufSize;
90          this.backlogSize = backlogSize;
91          this.socksProxyAddress = socksProxyAddress;
92          this.socksProxyUsername = socksProxyUsername;
93          this.socksProxyPassword = socksProxyPassword;
94      }
95  
96      /**
97       * @see Builder#setSelectInterval(TimeValue)
98       */
99      public TimeValue getSelectInterval() {
100         return this.selectInterval;
101     }
102 
103     /**
104      * @see Builder#setIoThreadCount(int)
105      */
106     public int getIoThreadCount() {
107         return this.ioThreadCount;
108     }
109 
110     /**
111      * @see Builder#setSoTimeout(Timeout)
112      */
113     public Timeout getSoTimeout() {
114         return soTimeout;
115     }
116 
117     /**
118      * @see Builder#setSoReuseAddress(boolean)
119      */
120     public boolean isSoReuseAddress() {
121         return soReuseAddress;
122     }
123 
124     /**
125      * @see Builder#setSoLinger(TimeValue)
126      */
127     public TimeValue getSoLinger() {
128         return soLinger;
129     }
130 
131     /**
132      * @see Builder#setSoKeepAlive(boolean)
133      */
134     public boolean isSoKeepalive() {
135         return this.soKeepAlive;
136     }
137 
138     /**
139      * @see Builder#setTcpNoDelay(boolean)
140      */
141     public boolean isTcpNoDelay() {
142         return tcpNoDelay;
143     }
144 
145     /**
146      * @see Builder#setTrafficClass(int)
147      *
148      * @since 5.1
149      */
150     public int getTrafficClass() {
151         return trafficClass;
152     }
153 
154     /**
155      * @see Builder#setSndBufSize(int)
156      */
157     public int getSndBufSize() {
158         return sndBufSize;
159     }
160 
161     /**
162      * @see Builder#setRcvBufSize(int)
163      */
164     public int getRcvBufSize() {
165         return rcvBufSize;
166     }
167 
168     /**
169      * @see Builder#setBacklogSize(int)
170      */
171     public int getBacklogSize() {
172         return backlogSize;
173     }
174 
175     /**
176      * @see Builder#setSocksProxyAddress(SocketAddress)
177      */
178     public SocketAddress getSocksProxyAddress() {
179         return this.socksProxyAddress;
180     }
181 
182     /**
183      * @see Builder#setSocksProxyUsername(String)
184      */
185     public String getSocksProxyUsername() {
186         return this.socksProxyUsername;
187     }
188 
189     /**
190      * @see Builder#setSocksProxyAddress(SocketAddress)
191      */
192     public String getSocksProxyPassword() {
193         return this.socksProxyPassword;
194     }
195 
196     public static Builder custom() {
197         return new Builder();
198     }
199 
200     public static Builder copy(final IOReactorConfig config) {
201         Args.notNull(config, "I/O reactor config");
202         return new Builder()
203             .setSelectInterval(config.getSelectInterval())
204             .setIoThreadCount(config.getIoThreadCount())
205             .setSoTimeout(config.getSoTimeout())
206             .setSoReuseAddress(config.isSoReuseAddress())
207             .setSoLinger(config.getSoLinger())
208             .setSoKeepAlive(config.isSoKeepalive())
209             .setTcpNoDelay(config.isTcpNoDelay())
210             .setSndBufSize(config.getSndBufSize())
211             .setRcvBufSize(config.getRcvBufSize())
212             .setBacklogSize(config.getBacklogSize())
213             .setSocksProxyAddress(config.getSocksProxyAddress())
214             .setSocksProxyUsername(config.getSocksProxyUsername())
215             .setSocksProxyPassword(config.getSocksProxyPassword());
216     }
217 
218     public static class Builder {
219 
220         private static int defaultMaxIOThreadCount = -1;
221 
222         /**
223          * Gets the default value for {@code ioThreadCount}. Returns
224          * {@link Runtime#availableProcessors()} if
225          * {@link #setDefaultMaxIOThreadCount(int)} was called with a value less &lt;= 0.
226          *
227          * @return the default value for ioThreadCount.
228          * @since 4.4.10
229          */
230         public static int getDefaultMaxIOThreadCount() {
231             return defaultMaxIOThreadCount > 0 ? defaultMaxIOThreadCount : Runtime.getRuntime().availableProcessors();
232         }
233 
234         /**
235          * Sets the default value for {@code ioThreadCount}. Use a value &lt;= 0 to
236          * cause {@link #getDefaultMaxIOThreadCount()} to return
237          * {@link Runtime#availableProcessors()}.
238          *
239          * @param defaultMaxIOThreadCount
240          *            the default value for ioThreadCount.
241          * @since 4.4.10
242          */
243         public static void setDefaultMaxIOThreadCount(final int defaultMaxIOThreadCount) {
244             Builder.defaultMaxIOThreadCount = defaultMaxIOThreadCount;
245         }
246 
247         private TimeValue selectInterval;
248         private int ioThreadCount;
249         private Timeout  soTimeout;
250         private boolean soReuseAddress;
251         private TimeValue soLinger;
252         private boolean soKeepAlive;
253         private boolean tcpNoDelay;
254         private int trafficClass;
255         private int sndBufSize;
256         private int rcvBufSize;
257         private int backlogSize;
258         private SocketAddress socksProxyAddress;
259         private String socksProxyUsername;
260         private String socksProxyPassword;
261 
262         Builder() {
263             this.selectInterval = TimeValue.ofSeconds(1);
264             this.ioThreadCount = Builder.getDefaultMaxIOThreadCount();
265             this.soTimeout = Timeout.ZERO_MILLISECONDS;
266             this.soReuseAddress = false;
267             this.soLinger = TimeValue.NEG_ONE_SECOND;
268             this.soKeepAlive = false;
269             this.tcpNoDelay = true;
270             this.trafficClass = 0;
271             this.sndBufSize = 0;
272             this.rcvBufSize = 0;
273             this.backlogSize = 0;
274             this.socksProxyAddress = null;
275             this.socksProxyUsername = null;
276             this.socksProxyPassword = null;
277         }
278 
279         /**
280          * Determines time interval at which the I/O reactor wakes up to check for timed out sessions
281          * and session requests.
282          * <p>
283          * Default: {@code 1000} milliseconds.
284          * </p>
285          */
286         public Builder setSelectInterval(final TimeValue selectInterval) {
287             this.selectInterval = selectInterval;
288             return this;
289         }
290 
291         /**
292          * Determines the number of I/O dispatch threads to be used by the I/O reactor.
293          * <p>
294          * Default: {@code 2}
295          * </p>
296          */
297         public Builder setIoThreadCount(final int ioThreadCount) {
298             this.ioThreadCount = ioThreadCount;
299             return this;
300         }
301 
302         /**
303          * Determines the default socket timeout value for non-blocking I/O operations.
304          * <p>
305          * Default: {@code 0} (no timeout)
306          * </p>
307          *
308          * @see java.net.SocketOptions#SO_TIMEOUT
309          */
310         public Builder setSoTimeout(final int soTimeout, final TimeUnit timeUnit) {
311             this.soTimeout = Timeout.of(soTimeout, timeUnit);
312             return this;
313         }
314 
315         /**
316          * Determines the default socket timeout value for non-blocking I/O operations.
317          * <p>
318          * Default: {@code 0} (no timeout)
319          * </p>
320          *
321          * @see java.net.SocketOptions#SO_TIMEOUT
322          */
323         public Builder setSoTimeout(final Timeout soTimeout) {
324             this.soTimeout = soTimeout;
325             return this;
326         }
327 
328         /**
329          * Determines the default value of the {@link java.net.SocketOptions#SO_REUSEADDR} parameter
330          * for newly created sockets.
331          * <p>
332          * Default: {@code false}
333          * </p>
334          *
335          * @see java.net.SocketOptions#SO_REUSEADDR
336          */
337         public Builder setSoReuseAddress(final boolean soReuseAddress) {
338             this.soReuseAddress = soReuseAddress;
339             return this;
340         }
341 
342         /**
343          * Determines the default value of the {@link java.net.SocketOptions#SO_LINGER} parameter
344          * for newly created sockets.
345          * <p>
346          * Default: {@code -1}
347          * </p>
348          *
349          * @see java.net.SocketOptions#SO_LINGER
350          */
351         public Builder setSoLinger(final int soLinger, final TimeUnit timeUnit) {
352             this.soLinger = TimeValue.of(soLinger, timeUnit);
353             return this;
354         }
355 
356         /**
357          * Determines the default value of the {@link java.net.SocketOptions#SO_LINGER} parameter
358          * for newly created sockets.
359          * <p>
360          * Default: {@code -1}
361          * </p>
362          *
363          * @see java.net.SocketOptions#SO_LINGER
364          */
365         public Builder setSoLinger(final TimeValue soLinger) {
366             this.soLinger = soLinger;
367             return this;
368         }
369 
370         /**
371          * Determines the default value of the {@link java.net.SocketOptions#SO_KEEPALIVE} parameter
372          * for newly created sockets.
373          * <p>
374          * Default: {@code -1}
375          * </p>
376          *
377          * @see java.net.SocketOptions#SO_KEEPALIVE
378          */
379         public Builder setSoKeepAlive(final boolean soKeepAlive) {
380             this.soKeepAlive = soKeepAlive;
381             return this;
382         }
383 
384         /**
385          * Determines the default value of the {@link java.net.SocketOptions#TCP_NODELAY} parameter
386          * for newly created sockets.
387          * <p>
388          * Default: {@code false}
389          * </p>
390          *
391          * @see java.net.SocketOptions#TCP_NODELAY
392          */
393         public Builder setTcpNoDelay(final boolean tcpNoDelay) {
394             this.tcpNoDelay = tcpNoDelay;
395             return this;
396         }
397 
398         /**
399          * Determines the default value of the {@link java.net.SocketOptions#IP_TOS} parameter
400          * for newly created sockets.
401          * <p>
402          * Default: {@code 0}
403          * </p>
404          *
405          * @see java.net.SocketOptions#IP_TOS
406          *
407          * @since 5.1
408          */
409         public Builder setTrafficClass(final int trafficClass) {
410             this.trafficClass = trafficClass;
411             return this;
412         }
413 
414         /**
415          * Determines the default value of the {@link java.net.SocketOptions#SO_SNDBUF} parameter
416          * for newly created sockets.
417          * <p>
418          * Default: {@code 0} (system default)
419          * </p>
420          *
421          * @see java.net.SocketOptions#SO_SNDBUF
422          */
423         public Builder setSndBufSize(final int sndBufSize) {
424             this.sndBufSize = sndBufSize;
425             return this;
426         }
427 
428         /**
429          * Determines the default value of the {@link java.net.SocketOptions#SO_RCVBUF} parameter
430          * for newly created sockets.
431          * <p>
432          * Default: {@code 0} (system default)
433          * </p>
434          *
435          * @see java.net.SocketOptions#SO_RCVBUF
436          */
437         public Builder setRcvBufSize(final int rcvBufSize) {
438             this.rcvBufSize = rcvBufSize;
439             return this;
440         }
441 
442         /**
443          * Determines the default backlog size value for server sockets binds.
444          * <p>
445          * Default: {@code 0} (system default)
446          * </p>
447          *
448          * @since 4.4
449          */
450         public Builder setBacklogSize(final int backlogSize) {
451             this.backlogSize = backlogSize;
452             return this;
453         }
454 
455         /**
456          * The address of the SOCKS proxy to use.
457          */
458         public Builder setSocksProxyAddress(final SocketAddress socksProxyAddress) {
459             this.socksProxyAddress = socksProxyAddress;
460             return this;
461         }
462 
463         /**
464          * The username to provide to the SOCKS proxy for username/password authentication.
465          */
466         public Builder setSocksProxyUsername(final String socksProxyUsername) {
467             this.socksProxyUsername = socksProxyUsername;
468             return this;
469         }
470 
471         /**
472          * The password to provide to the SOCKS proxy for username/password authentication.
473          */
474         public Builder setSocksProxyPassword(final String socksProxyPassword) {
475             this.socksProxyPassword = socksProxyPassword;
476             return this;
477         }
478 
479         public IOReactorConfig build() {
480             return new IOReactorConfig(
481                     selectInterval != null ? selectInterval : TimeValue.ofSeconds(1),
482                     ioThreadCount,
483                     Timeout.defaultsToDisabled(soTimeout),
484                     soReuseAddress,
485                     TimeValue.defaultsToNegativeOneMillisecond(soLinger),
486                     soKeepAlive,
487                     tcpNoDelay,
488                     trafficClass,
489                     sndBufSize, rcvBufSize, backlogSize,
490                     socksProxyAddress, socksProxyUsername, socksProxyPassword);
491         }
492 
493     }
494 
495     @Override
496     public String toString() {
497         final StringBuilder builder = new StringBuilder();
498         builder.append("[selectInterval=").append(this.selectInterval)
499                 .append(", ioThreadCount=").append(this.ioThreadCount)
500                 .append(", soTimeout=").append(this.soTimeout)
501                 .append(", soReuseAddress=").append(this.soReuseAddress)
502                 .append(", soLinger=").append(this.soLinger)
503                 .append(", soKeepAlive=").append(this.soKeepAlive)
504                 .append(", tcpNoDelay=").append(this.tcpNoDelay)
505                 .append(", trafficClass=").append(this.trafficClass)
506                 .append(", sndBufSize=").append(this.sndBufSize)
507                 .append(", rcvBufSize=").append(this.rcvBufSize)
508                 .append(", backlogSize=").append(this.backlogSize)
509                 .append(", socksProxyAddress=").append(this.socksProxyAddress)
510                 .append("]");
511         return builder.toString();
512     }
513 
514 }