1 /*
2  * Copyright (c) 2011-2017 Contributors to the Eclipse Foundation
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License 2.0 which is available at
6  * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7  * which is available at https://www.apache.org/licenses/LICENSE-2.0.
8  *
9  * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10  */
11 
12 module hunt.net.TcpSslOptions;
13 
14 import hunt.net.KeyCertOptions;
15 import hunt.net.NetworkOptions;
16 import hunt.net.OpenSSLEngineOptions;
17 import hunt.net.PemKeyCertOptions;
18 
19 import hunt.Exceptions;
20 import hunt.io.TcpStreamOptions;
21 
22 import core.time;
23 
24 /**
25  * Base class. TCP and SSL related options
26  *
27  * @author <a href="http://tfox.org">Tim Fox</a>
28  */
29 class TcpSslOptions : NetworkOptions {
30 
31     /**
32      * The default value of TCP-no-delay = true (Nagle disabled)
33      */
34     enum bool DEFAULT_TCP_NO_DELAY = true;
35 
36     /**
37      * The default value of TCP keep alive = false
38      */
39     enum bool DEFAULT_TCP_KEEP_ALIVE = false;
40 
41     /**
42      * The default value of SO_linger = -1
43      */
44     enum int DEFAULT_SO_LINGER = -1;
45 
46     /**
47      * The default value of Netty use pooled buffers = false
48      */
49     enum bool DEFAULT_USE_POOLED_BUFFERS = false;
50 
51     /**
52      * SSL enable by default = false
53      */
54     enum bool DEFAULT_SSL = false;
55 
56     /**
57      * Default idle timeout = 0
58      */
59     enum Duration DEFAULT_IDLE_TIMEOUT = Duration.zero;
60 
61     // http://www.tldp.org/HOWTO/TCP-Keepalive-HOWTO/usingkeepalive.html
62     /// the interval between the last data packet sent (simple ACKs are not considered data) and the first keepalive probe; 
63     /// after the connection is marked to need keepalive, this counter is not used any further 
64     enum Duration DEFAULT_KEEPALIVE_WAITTIME = 7200.seconds;
65 
66     /// the interval between subsequential keepalive probes, regardless of what the connection has exchanged in the meantime 
67     enum Duration DEFAULT_KEEPALIVE_INTERVAL = 75.seconds;
68 
69     /// the number of unacknowledged probes to send before considering the connection dead and notifying the application layer 
70     enum int DEFAULT_KEEPALIVE_PROBES = 9;
71 
72     /**
73      * Default use alpn = false
74      */
75     enum bool DEFAULT_USE_ALPN = false;
76 
77     /**
78      * The default SSL engine options = null (autoguess)
79      */
80     // enum SSLEngineOptions DEFAULT_SSL_ENGINE = null;
81 
82     /**
83      * The default ENABLED_SECURE_TRANSPORT_PROTOCOLS value = { "SSLv2Hello", "TLSv1", "TLSv1.1", "TLSv1.2" }
84      * <p/>
85      * SSLv3 is NOT enabled due to POODLE vulnerability http://en.wikipedia.org/wiki/POODLE
86      * <p/>
87      * "SSLv2Hello" is NOT enabled since it's disabled by default since JDK7
88      */
89     enum string[] DEFAULT_ENABLED_SECURE_TRANSPORT_PROTOCOLS = ["TLSv1", "TLSv1.1", "TLSv1.2"];
90 
91     /**
92      * The default TCP_FASTOPEN value = false
93      */
94     enum bool DEFAULT_TCP_FAST_OPEN = false;
95 
96     /**
97      * The default TCP_CORK value = false
98      */
99     enum bool DEFAULT_TCP_CORK = false;
100 
101     /**
102      * The default TCP_QUICKACK value = false
103      */
104     enum bool DEFAULT_TCP_QUICKACK = false;
105 
106     /**
107      * The default value of SSL handshake timeout = 10 SECONDS
108      */
109     enum Duration DEFAULT_SSL_HANDSHAKE_TIMEOUT = 10.seconds;
110 
111     enum int DEFAULT_RETRY_TIMES = 5;
112     enum Duration DEFAULT_RETRY_INTERVAL = 2.seconds;
113 
114 
115     private bool tcpNoDelay;
116     private bool tcpKeepAlive;
117     private int soLinger;
118     private bool usePooledBuffers;
119     private Duration idleTimeout;
120     private Duration keepaliveWaitTime = DEFAULT_KEEPALIVE_WAITTIME;
121     private Duration keepaliveInterval = DEFAULT_KEEPALIVE_INTERVAL;
122     private int keepaliveProbes = DEFAULT_KEEPALIVE_PROBES;
123     private bool ssl;
124     private Duration sslHandshakeTimeout;
125     private KeyCertOptions keyCertOptions;
126     // private TrustOptions trustOptions;
127     // private Set!(string) enabledCipherSuites;
128     // private ArrayList!(string) crlPaths;
129     // private ArrayList!(Buffer) crlValues;
130     private bool useAlpn;
131     private OpenSSLEngineOptions sslEngineOptions;
132     // private Set!(string) enabledSecureTransportProtocols;
133     private bool tcpFastOpen;
134     private bool tcpCork;
135     private bool tcpQuickAck;
136 
137     private int retryTimes = DEFAULT_RETRY_TIMES;
138     private Duration retryInterval = DEFAULT_RETRY_INTERVAL;
139 
140     /**
141      * Default constructor
142      */
143     this() {
144         super();
145         initialize();
146     }
147 
148     /**
149      * Copy constructor
150      *
151      * @param other  the options to copy
152      */
153     this(TcpSslOptions other) {
154         super(other);
155         this.tcpNoDelay = other.isTcpNoDelay();
156         this.tcpKeepAlive = other.isTcpKeepAlive();
157         this.soLinger = other.getSoLinger();
158         // this.usePooledBuffers = other.isUsePooledBuffers();
159         
160         this.idleTimeout = other.getIdleTimeout();
161         this.keepaliveWaitTime = other.keepaliveWaitTime;
162         this.keepaliveInterval = other.keepaliveInterval;
163         this.keepaliveProbes = other.keepaliveProbes;
164 
165         this.ssl = other.isSsl();
166         this.sslHandshakeTimeout = other.sslHandshakeTimeout;
167         this.keyCertOptions = other.getKeyCertOptions() !is null ? other.getKeyCertOptions().copy() : null;
168         // this.trustOptions = other.getTrustOptions() !is null ? other.getTrustOptions().copy() : null;
169         // this.enabledCipherSuites = other.getEnabledCipherSuites() is null ? new LinkedHashSet<>() : new LinkedHashSet<>(other.getEnabledCipherSuites());
170         // this.crlPaths = new ArrayList<>(other.getCrlPaths());
171         // this.crlValues = new ArrayList<>(other.getCrlValues());
172         this.useAlpn = other.useAlpn;
173         // this.sslEngineOptions = other.sslEngineOptions !is null ? other.sslEngineOptions.copy() : null;
174         // this.enabledSecureTransportProtocols = other.getEnabledSecureTransportProtocols() is null ? new LinkedHashSet<>() : new LinkedHashSet<>(other.getEnabledSecureTransportProtocols());
175         this.tcpFastOpen = other.isTcpFastOpen();
176         this.tcpCork = other.isTcpCork();
177         this.tcpQuickAck = other.isTcpQuickAck();
178 
179         this.retryTimes = other.retryTimes;
180         this.retryInterval = other.retryInterval;
181     }
182 
183     private void initialize() {
184         tcpNoDelay = DEFAULT_TCP_NO_DELAY;
185         tcpKeepAlive = DEFAULT_TCP_KEEP_ALIVE;
186         soLinger = DEFAULT_SO_LINGER;
187         usePooledBuffers = DEFAULT_USE_POOLED_BUFFERS;
188         idleTimeout = DEFAULT_IDLE_TIMEOUT;
189 
190         keepaliveWaitTime = 15.seconds;
191         keepaliveInterval = 3.seconds;
192         keepaliveProbes = 5;
193 
194         ssl = DEFAULT_SSL;
195         sslHandshakeTimeout = DEFAULT_SSL_HANDSHAKE_TIMEOUT;
196         // enabledCipherSuites = new LinkedHashSet<>();
197         // crlPaths = new ArrayList<>();
198         // crlValues = new ArrayList<>();
199         useAlpn = DEFAULT_USE_ALPN;
200         // sslEngineOptions = DEFAULT_SSL_ENGINE;
201         // enabledSecureTransportProtocols = new LinkedHashSet<>(DEFAULT_ENABLED_SECURE_TRANSPORT_PROTOCOLS);
202         tcpFastOpen = DEFAULT_TCP_FAST_OPEN;
203         tcpCork = DEFAULT_TCP_CORK;
204         tcpQuickAck = DEFAULT_TCP_QUICKACK;
205     }
206 
207     /**
208      * @return TCP no delay enabled ?
209      */
210     bool isTcpNoDelay() {
211         return tcpNoDelay;
212     }
213 
214     /**
215      * Set whether TCP no delay is enabled
216      *
217      * @param tcpNoDelay true if TCP no delay is enabled (Nagle disabled)
218      * @return a reference to this, so the API can be used fluently
219      */
220     TcpSslOptions setTcpNoDelay(bool tcpNoDelay) {
221         this.tcpNoDelay = tcpNoDelay;
222         return this;
223     }
224 
225     /**
226      * @return is TCP keep alive enabled?
227      */
228     bool isTcpKeepAlive() {
229         return tcpKeepAlive;
230     }
231 
232     /**
233      * Set whether TCP keep alive is enabled
234      *
235      * @param tcpKeepAlive true if TCP keep alive is enabled
236      * @return a reference to this, so the API can be used fluently
237      */
238     TcpSslOptions setTcpKeepAlive(bool tcpKeepAlive) {
239         this.tcpKeepAlive = tcpKeepAlive;
240         return this;
241     }
242 
243     /**
244      *
245      * @return is SO_linger enabled
246      */
247     int getSoLinger() {
248         return soLinger;
249     }
250 
251     /**
252      * Set whether SO_linger keep alive is enabled
253      *
254      * @param soLinger true if SO_linger is enabled
255      * @return a reference to this, so the API can be used fluently
256      */
257     TcpSslOptions setSoLinger(int soLinger) {
258         if (soLinger < 0 && soLinger != DEFAULT_SO_LINGER) {
259             throw new IllegalArgumentException("soLinger must be >= 0");
260         }
261         this.soLinger = soLinger;
262         return this;
263     }
264 
265     /**
266      * Set the idle timeout, default time unit is seconds. Zero means don't timeout.
267      * This determines if a connection will timeout and be closed if no data is received within the timeout.
268      *
269      * If you want change default time unit, use {@link #setIdleTimeoutUnit(TimeUnit)}
270      *
271      * @param idleTimeout  the timeout, in seconds
272      * @return a reference to this, so the API can be used fluently
273      */
274     TcpSslOptions setIdleTimeout(Duration value) {
275         if (value < Duration.zero) {
276             throw new IllegalArgumentException("idleTimeout must be >= 0");
277         }
278         this.idleTimeout = value;
279         return this;
280     }
281 
282     /**
283      * @return the idle timeout, in time unit specified by {@link #getIdleTimeoutUnit()}.
284      */
285     Duration getIdleTimeout() {
286         return idleTimeout;
287     }
288 
289     TcpSslOptions setKeepaliveWaitTime(Duration value) {
290         if (value < Duration.zero) {
291             throw new IllegalArgumentException("keepaliveWaitTime must be >= 0");
292         }
293         this.keepaliveWaitTime = value;
294         return this;
295     }
296 
297     Duration getKeepaliveWaitTime() {
298         return keepaliveWaitTime;
299     }
300 
301     TcpSslOptions setKeepaliveInterval(Duration value) {
302         if (value < Duration.zero) {
303             throw new IllegalArgumentException("keepaliveInterval must be >= 0");
304         }
305         this.keepaliveInterval = value;
306         return this;
307     }
308 
309     Duration getKeepaliveInterval() {
310         return keepaliveInterval;
311     }
312 
313     TcpSslOptions setKeepaliveProbes(int times) {
314         if (times <=0) {
315             throw new IllegalArgumentException("keepaliveProbes must be >= 1");
316         }
317         this.keepaliveProbes = times;
318         return this;
319     }
320 
321     int getKeepaliveProbes() {
322         return keepaliveProbes;
323     }
324 
325     /**
326      *
327      * @return is SSL/TLS enabled?
328      */
329     bool isSsl() {
330         return ssl;
331     }
332 
333     /**
334      * Set whether SSL/TLS is enabled
335      *
336      * @param ssl  true if enabled
337      * @return a reference to this, so the API can be used fluently
338      */
339     TcpSslOptions setSsl(bool ssl) {
340         this.ssl = ssl;
341         return this;
342     }
343 
344     /**
345      * @return the key/cert options
346      */
347     
348     KeyCertOptions getKeyCertOptions() {
349         return keyCertOptions;
350     }
351 
352     /**
353      * Set the key/cert options.
354      *
355      * @param options the key store options
356      * @return a reference to this, so the API can be used fluently
357      */
358     
359     TcpSslOptions setKeyCertOptions(KeyCertOptions options) {
360         this.keyCertOptions = options;
361         return this;
362     }
363 
364     // /**
365     //  * Get the key/cert options in jks format, aka Java keystore.
366     //  *
367     //  * @return the key/cert options in jks format, aka Java keystore.
368     //  */
369     // JksOptions getKeyStoreOptions() {
370     //     return keyCertOptions instanceof JksOptions ? (JksOptions) keyCertOptions : null;
371     // }
372 
373     // /**
374     //  * Set the key/cert options in jks format, aka Java keystore.
375     //  * @param options the key store in jks format
376     //  * @return a reference to this, so the API can be used fluently
377     //  */
378     // TcpSslOptions setKeyStoreOptions(JksOptions options) {
379     //     this.keyCertOptions = options;
380     //     return this;
381     // }
382 
383     // /**
384     //  * Get the key/cert options in pfx format.
385     //  *
386     //  * @return the key/cert options in pfx format.
387     //  */
388     // PfxOptions getPfxKeyCertOptions() {
389     //     return keyCertOptions instanceof PfxOptions ? (PfxOptions) keyCertOptions : null;
390     // }
391 
392     // /**
393     //  * Set the key/cert options in pfx format.
394     //  * @param options the key cert options in pfx format
395     //  * @return a reference to this, so the API can be used fluently
396     //  */
397     // TcpSslOptions setPfxKeyCertOptions(PfxOptions options) {
398     //     this.keyCertOptions = options;
399     //     return this;
400     // }
401 
402     /**
403      * Get the key/cert store options in pem format.
404      *
405      * @return the key/cert store options in pem format.
406      */
407     PemKeyCertOptions getPemKeyCertOptions() {
408         return cast(PemKeyCertOptions) keyCertOptions;
409     }
410 
411     /**
412      * Set the key/cert store options in pem format.
413      * @param options the options in pem format
414      * @return a reference to this, so the API can be used fluently
415      */
416     TcpSslOptions setPemKeyCertOptions(PemKeyCertOptions options) {
417         this.keyCertOptions = options;
418         return this;
419     }
420 
421     // /**
422     //  * @return the trust options
423     //  */
424     // TrustOptions getTrustOptions() {
425     //     return trustOptions;
426     // }
427 
428     // /**
429     //  * Set the trust options.
430     //  * @param options the trust options
431     //  * @return a reference to this, so the API can be used fluently
432     //  */
433     // TcpSslOptions setTrustOptions(TrustOptions options) {
434     //     this.trustOptions = options;
435     //     return this;
436     // }
437 
438     // /**
439     //  * Get the trust options in jks format, aka Java truststore
440     //  *
441     //  * @return the trust options in jks format, aka Java truststore
442     //  */
443     // JksOptions getTrustStoreOptions() {
444     //     return trustOptions instanceof JksOptions ? (JksOptions) trustOptions : null;
445     // }
446 
447     // /**
448     //  * Set the trust options in jks format, aka Java truststore
449     //  * @param options the trust options in jks format
450     //  * @return a reference to this, so the API can be used fluently
451     //  */
452     // TcpSslOptions setTrustStoreOptions(JksOptions options) {
453     //     this.trustOptions = options;
454     //     return this;
455     // }
456 
457     // /**
458     //  * Get the trust options in pfx format
459     //  *
460     //  * @return the trust options in pfx format
461     //  */
462     // PfxOptions getPfxTrustOptions() {
463     //     return trustOptions instanceof PfxOptions ? (PfxOptions) trustOptions : null;
464     // }
465 
466     // /**
467     //  * Set the trust options in pfx format
468     //  * @param options the trust options in pfx format
469     //  * @return a reference to this, so the API can be used fluently
470     //  */
471     // TcpSslOptions setPfxTrustOptions(PfxOptions options) {
472     //     this.trustOptions = options;
473     //     return this;
474     // }
475 
476     // /**
477     //  * Get the trust options in pem format
478     //  *
479     //  * @return the trust options in pem format
480     //  */
481     // PemTrustOptions getPemTrustOptions() {
482     //     return trustOptions instanceof PemTrustOptions ? (PemTrustOptions) trustOptions : null;
483     // }
484 
485     // /**
486     //  * Set the trust options in pem format
487     //  * @param options the trust options in pem format
488     //  * @return a reference to this, so the API can be used fluently
489     //  */
490     // TcpSslOptions setPemTrustOptions(PemTrustOptions options) {
491     //     this.trustOptions = options;
492     //     return this;
493     // }
494 
495     /**
496      * Add an enabled cipher suite, appended to the ordered suites.
497      *
498      * @param suite  the suite
499      * @return a reference to this, so the API can be used fluently
500      */
501     // TcpSslOptions addEnabledCipherSuite(string suite) {
502     //     enabledCipherSuites.add(suite);
503     //     return this;
504     // }
505 
506     // /**
507     //  *
508     //  * @return the enabled cipher suites
509     //  */
510     // Set!(string) getEnabledCipherSuites() {
511     //     return enabledCipherSuites;
512     // }
513 
514     // /**
515     //  *
516     //  * @return the CRL (Certificate revocation list) paths
517     //  */
518     // List!(string) getCrlPaths() {
519     //     return crlPaths;
520     // }
521 
522     // /**
523     //  * Add a CRL path
524     //  * @param crlPath  the path
525     //  * @return a reference to this, so the API can be used fluently
526     //  * @throws NullPointerException
527     //  */
528     // TcpSslOptions addCrlPath(string crlPath) throws NullPointerException {
529     //     Objects.requireNonNull(crlPath, "No null crl accepted");
530     //     crlPaths.add(crlPath);
531     //     return this;
532     // }
533 
534     // /**
535     //  * Get the CRL values
536     //  *
537     //  * @return the list of values
538     //  */
539     // List!(Buffer) getCrlValues() {
540     //     return crlValues;
541     // }
542 
543     // /**
544     //  * Add a CRL value
545     //  *
546     //  * @param crlValue  the value
547     //  * @return a reference to this, so the API can be used fluently
548     //  * @throws NullPointerException
549     //  */
550     // TcpSslOptions addCrlValue(Buffer crlValue) throws NullPointerException {
551     //     Objects.requireNonNull(crlValue, "No null crl accepted");
552     //     crlValues.add(crlValue);
553     //     return this;
554     // }
555 
556     /**
557      * @return whether to use or not Application-Layer Protocol Negotiation
558      */
559     bool isUseAlpn() {
560         return useAlpn;
561     }
562 
563     /**
564      * Set the ALPN usage.
565      *
566      * @param useAlpn true when Application-Layer Protocol Negotiation should be used
567      */
568     TcpSslOptions setUseAlpn(bool useAlpn) {
569         this.useAlpn = useAlpn;
570         return this;
571     }
572 
573     /**
574      * @return the SSL engine implementation to use
575      */
576     // SSLEngineOptions getSslEngineOptions() {
577     //     return sslEngineOptions;
578     // }
579 
580     /**
581      * Set to use SSL engine implementation to use.
582      *
583      * @param sslEngineOptions the ssl engine to use
584      * @return a reference to this, so the API can be used fluently
585      */
586     // TcpSslOptions setSslEngineOptions(SSLEngineOptions sslEngineOptions) {
587     //     this.sslEngineOptions = sslEngineOptions;
588     //     return this;
589     // }
590 
591     // JdkSSLEngineOptions getJdkSslEngineOptions() {
592     //     return sslEngineOptions instanceof JdkSSLEngineOptions ? (JdkSSLEngineOptions) sslEngineOptions : null;
593     // }
594 
595     // TcpSslOptions setJdkSslEngineOptions(JdkSSLEngineOptions sslEngineOptions) {
596     //     return setSslEngineOptions(sslEngineOptions);
597     // }
598 
599     OpenSSLEngineOptions getOpenSslEngineOptions() {
600         return this.sslEngineOptions;
601     }
602 
603     TcpSslOptions setOpenSslEngineOptions(OpenSSLEngineOptions sslEngineOptions) {
604         this.sslEngineOptions = sslEngineOptions;
605         return this;
606     }
607 
608     // /**
609     //  * Sets the list of enabled SSL/TLS protocols.
610     //  *
611     //  * @param enabledSecureTransportProtocols  the SSL/TLS protocols to enable
612     //  * @return a reference to this, so the API can be used fluently
613     //  */
614     // TcpSslOptions setEnabledSecureTransportProtocols(Set!(string) enabledSecureTransportProtocols) {
615     //     this.enabledSecureTransportProtocols = enabledSecureTransportProtocols;
616     //     return this;
617     // }
618 
619     // /**
620     //  * Add an enabled SSL/TLS protocols, appended to the ordered protocols.
621     //  *
622     //  * @param protocol  the SSL/TLS protocol to enable
623     //  * @return a reference to this, so the API can be used fluently
624     //  */
625     // TcpSslOptions addEnabledSecureTransportProtocol(string protocol) {
626     //     enabledSecureTransportProtocols.add(protocol);
627     //     return this;
628     // }
629 
630     // /**
631     //  * Removes an enabled SSL/TLS protocol from the ordered protocols.
632     //  *
633     //  * @param protocol the SSL/TLS protocol to disable
634     //  * @return a reference to this, so the API can be used fluently
635     //  */
636     // TcpSslOptions removeEnabledSecureTransportProtocol(string protocol) {
637     //     enabledSecureTransportProtocols.remove(protocol);
638     //     return this;
639     // }
640 
641     /**
642      * @return wether {@code TCP_FASTOPEN} option is enabled
643      */
644     bool isTcpFastOpen() {
645         return tcpFastOpen;
646     }
647 
648     /**
649      * Enable the {@code TCP_FASTOPEN} option - only with linux native transport.
650      *
651      * @param tcpFastOpen the fast open value
652      */
653     TcpSslOptions setTcpFastOpen(bool tcpFastOpen) {
654         this.tcpFastOpen = tcpFastOpen;
655         return this;
656     }
657 
658     /**
659      * @return wether {@code TCP_CORK} option is enabled
660      */
661     bool isTcpCork() {
662         return tcpCork;
663     }
664 
665     /**
666      * Enable the {@code TCP_CORK} option - only with linux native transport.
667      *
668      * @param tcpCork the cork value
669      */
670     TcpSslOptions setTcpCork(bool tcpCork) {
671         this.tcpCork = tcpCork;
672         return this;
673     }
674 
675     /**
676      * @return wether {@code TCP_QUICKACK} option is enabled
677      */
678     bool isTcpQuickAck() {
679         return tcpQuickAck;
680     }
681 
682     /**
683      * Enable the {@code TCP_QUICKACK} option - only with linux native transport.
684      *
685      * @param tcpQuickAck the quick ack value
686      */
687     TcpSslOptions setTcpQuickAck(bool tcpQuickAck) {
688         this.tcpQuickAck = tcpQuickAck;
689         return this;
690     }
691 
692     /**
693      * Returns the enabled SSL/TLS protocols
694      * @return the enabled protocols
695      */
696     // Set!(string) getEnabledSecureTransportProtocols() {
697     //     return new LinkedHashSet<>(enabledSecureTransportProtocols);
698     // }
699 
700     /**
701      * @return the SSL handshake timeout, in time unit specified by {@link #getSslHandshakeTimeoutUnit()}.
702      */
703     Duration getSslHandshakeTimeout() {
704         return sslHandshakeTimeout;
705     }
706 
707     /**
708      * Set the SSL handshake timeout, default time unit is seconds.
709      *
710      * @param sslHandshakeTimeout the SSL handshake timeout to set, in milliseconds
711      * @return a reference to this, so the API can be used fluently
712      */
713     TcpSslOptions setSslHandshakeTimeout(Duration sslHandshakeTimeout) {
714         if (sslHandshakeTimeout < Duration.zero) {
715             throw new IllegalArgumentException("sslHandshakeTimeout must be >= 0");
716         }
717         this.sslHandshakeTimeout = sslHandshakeTimeout;
718         return this;
719     }
720 
721     override
722     TcpSslOptions setLogActivity(bool logEnabled) {
723         return cast(TcpSslOptions) super.setLogActivity(logEnabled);
724     }
725 
726     override
727     TcpSslOptions setSendBufferSize(int sendBufferSize) {
728         return cast(TcpSslOptions) super.setSendBufferSize(sendBufferSize);
729     }
730 
731     override
732     TcpSslOptions setReceiveBufferSize(int receiveBufferSize) {
733         return cast(TcpSslOptions) super.setReceiveBufferSize(receiveBufferSize);
734     }
735 
736     override
737     TcpSslOptions setTrafficClass(int trafficClass) {
738         return cast(TcpSslOptions) super.setTrafficClass(trafficClass);
739     }
740 
741     override
742     TcpSslOptions setReuseAddress(bool reuseAddress) {
743         return cast(TcpSslOptions) super.setReuseAddress(reuseAddress);
744     }
745 
746     override
747     TcpSslOptions setReusePort(bool reusePort) {
748         return cast(TcpSslOptions) super.setReusePort(reusePort);
749     }
750 
751     TcpSslOptions setRetryTimes(int times) {
752         if (times <= 0) {
753             throw new IllegalArgumentException("retryTimes must be >= 1");
754         }
755         this.retryTimes = times;
756         return this;
757     }
758 
759     int getRetryTimes() {
760         return retryTimes;
761     }
762 
763     TcpSslOptions setRetryInterval(Duration timeout) {
764         if (retryInterval < Duration.zero) {
765             throw new IllegalArgumentException("retryInterval must be >= 0");
766         }
767         this.retryInterval = timeout;
768         return this;
769     }
770 
771     Duration getRetryInterval() {
772         return retryInterval;
773     }
774 
775     override
776     bool opEquals(Object o) {
777         if (this is o) return true;
778         if (!super.opEquals(o)) return false;
779 
780         TcpSslOptions that = cast(TcpSslOptions) o;
781         if(that is null)
782             return false;
783 
784         if (idleTimeout != that.idleTimeout) return false;
785         if (keepaliveWaitTime != that.keepaliveWaitTime) return false;
786         if (keepaliveInterval != that.keepaliveInterval) return false;
787         if (keepaliveProbes != that.keepaliveProbes) return false;
788 
789 
790         if (soLinger != that.soLinger) return false;
791         if (ssl != that.ssl) return false;
792         if (tcpKeepAlive != that.tcpKeepAlive) return false;
793         if (tcpNoDelay != that.tcpNoDelay) return false;
794         if (tcpFastOpen != that.tcpFastOpen) return false;
795         if (tcpQuickAck != that.tcpQuickAck) return false;
796         if (tcpCork != that.tcpCork) return false;
797         if (usePooledBuffers != that.usePooledBuffers) return false;
798         // if (crlPaths !is null ? !crlPaths.equals(that.crlPaths) : that.crlPaths !is null) return false;
799         // if (crlValues !is null ? !crlValues.equals(that.crlValues) : that.crlValues !is null) return false;
800         // if (enabledCipherSuites !is null ? !enabledCipherSuites.equals(that.enabledCipherSuites) : that.enabledCipherSuites !is null)
801             // return false;
802         // if (keyCertOptions !is null ? !keyCertOptions.equals(that.keyCertOptions) : that.keyCertOptions !is null) return false;
803         // if (trustOptions !is null ? !trustOptions.equals(that.trustOptions) : that.trustOptions !is null) return false;
804         if (useAlpn != that.useAlpn) return false;
805         // if (sslEngineOptions !is null ? !sslEngineOptions.equals(that.sslEngineOptions) : that.sslEngineOptions !is null) return false;
806         // if (!enabledSecureTransportProtocols.equals(that.enabledSecureTransportProtocols)) return false;
807         if (retryTimes != that.retryTimes) return false;
808         if (retryInterval != that.retryInterval) return false;
809 
810         return true;
811     }
812 
813     override
814     size_t toHash() @trusted nothrow {
815         size_t result = super.toHash();
816         result = 31 * result + (tcpNoDelay ? 1 : 0);
817         result = 31 * result + (tcpFastOpen ? 1 : 0);
818         result = 31 * result + (tcpCork ? 1 : 0);
819         result = 31 * result + (tcpQuickAck ? 1 : 0);
820         result = 31 * result + (tcpKeepAlive ? 1 : 0);
821         result = 31 * result + soLinger;
822         result = 31 * result + (usePooledBuffers ? 1 : 0);
823         result = 31 * result + cast(size_t)idleTimeout.total!"msecs";
824         result = 31 * result + cast(size_t)keepaliveWaitTime.total!"msecs";
825         result = 31 * result + cast(size_t)keepaliveInterval.total!"msecs";
826         result = 31 * result + keepaliveProbes;
827         // result = 31 * result + (idleTimeoutUnit !is null ? idleTimeoutUnit.toHash() : 0);
828         result = 31 * result + (ssl ? 1 : 0);
829         // result = 31 * result + (keyCertOptions !is null ? keyCertOptions.toHash() : 0);
830         // result = 31 * result + (trustOptions !is null ? trustOptions.toHash() : 0);
831         // result = 31 * result + (enabledCipherSuites !is null ? enabledCipherSuites.toHash() : 0);
832         // result = 31 * result + (crlPaths !is null ? crlPaths.toHash() : 0);
833         // result = 31 * result + (crlValues !is null ? crlValues.toHash() : 0);
834         result = 31 * result + (useAlpn ? 1 : 0);
835         // result = 31 * result + (sslEngineOptions !is null ? sslEngineOptions.toHash() : 0);
836         // result = 31 * result + (enabledSecureTransportProtocols !is null ? enabledSecureTransportProtocols
837         //         .toHash() : 0);
838         result = 31 * result + retryTimes;
839         result = 31 * result + cast(size_t)retryInterval.total!"msecs";
840         return result;
841     }
842 
843     TcpStreamOptions toStreamOptions() {
844 
845         TcpStreamOptions streamOptions = new TcpStreamOptions();
846         streamOptions.isKeepalive = isTcpKeepAlive();
847         streamOptions.keepaliveTime = cast(int)getKeepaliveWaitTime().total!"seconds";
848         streamOptions.keepaliveInterval = cast(int)getKeepaliveInterval().total!"seconds";
849         streamOptions.retryTimes = getRetryTimes();
850         streamOptions.retryInterval = getRetryInterval();
851         int size = getReceiveBufferSize();
852         if(size > 0)
853             streamOptions.bufferSize = size;
854 
855         return streamOptions;
856     }   
857 }