Refresh IETF client/server models
[netconf.git] / transport / transport-tcp / src / main / java / org / opendaylight / netconf / transport / tcp / NioNettyImpl.java
1 /*
2  * Copyright (c) 2022 PANTHEON.tech, s.r.o. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.netconf.transport.tcp;
9
10 import io.netty.bootstrap.Bootstrap;
11 import io.netty.bootstrap.ServerBootstrap;
12 import io.netty.channel.ChannelOption;
13 import io.netty.channel.EventLoopGroup;
14 import io.netty.channel.nio.NioEventLoopGroup;
15 import io.netty.channel.socket.SocketChannelConfig;
16 import io.netty.channel.socket.nio.NioChannelOption;
17 import io.netty.channel.socket.nio.NioServerSocketChannel;
18 import io.netty.channel.socket.nio.NioSocketChannel;
19 import java.util.Map;
20 import java.util.concurrent.ThreadFactory;
21 import jdk.net.ExtendedSocketOptions;
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tcp.common.rev231228.tcp.common.grouping.Keepalives;
24 import org.slf4j.LoggerFactory;
25
26 @NonNullByDefault
27 final class NioNettyImpl extends AbstractNettyImpl {
28     // FIXME: all of this is a workaround for https://issues.apache.org/jira/browse/KARAF-7690
29     private abstract static class AbstractSupport {
30
31         abstract boolean configureKeepalives(SocketChannelConfig config);
32
33         abstract void configureKeepalives(ServerBootstrap bootstrap, Keepalives keepalives);
34
35         abstract void configureKeepalives(Bootstrap bootstrap, Keepalives keepalives);
36     }
37
38     private static final class Supported extends AbstractSupport {
39         private static final ChannelOption<Integer> TCP_KEEPIDLE =
40             NioChannelOption.of(ExtendedSocketOptions.TCP_KEEPIDLE);
41         private static final ChannelOption<Integer> TCP_KEEPCNT =
42             NioChannelOption.of(ExtendedSocketOptions.TCP_KEEPCOUNT);
43         private static final ChannelOption<Integer> TCP_KEEPINTVL =
44             NioChannelOption.of(ExtendedSocketOptions.TCP_KEEPINTERVAL);
45
46         @Override
47         boolean configureKeepalives(final SocketChannelConfig config) {
48             return config.setOptions(Map.of(
49                 ChannelOption.SO_KEEPALIVE, Boolean.TRUE, TCP_KEEPIDLE, 7200, TCP_KEEPCNT, 3, TCP_KEEPINTVL, 5));
50         }
51
52         @Override
53         void configureKeepalives(final ServerBootstrap bootstrap, final Keepalives keepalives) {
54             bootstrap
55                 .childOption(TCP_KEEPIDLE, keepalives.requireIdleTime().toJava())
56                 .childOption(TCP_KEEPCNT, keepalives.requireMaxProbes().toJava())
57                 .childOption(TCP_KEEPINTVL, keepalives.requireProbeInterval().toJava());
58         }
59
60         @Override
61         void configureKeepalives(final Bootstrap bootstrap, final Keepalives keepalives) {
62             bootstrap
63                 .option(TCP_KEEPIDLE, keepalives.requireIdleTime().toJava())
64                 .option(TCP_KEEPCNT, keepalives.requireMaxProbes().toJava())
65                 .option(TCP_KEEPINTVL, keepalives.requireProbeInterval().toJava());
66         }
67     }
68
69     private static final class Unsupported extends AbstractSupport {
70         @Override
71         boolean configureKeepalives(final SocketChannelConfig config) {
72             return false;
73         }
74
75         @Override
76         void configureKeepalives(final ServerBootstrap bootstrap, final Keepalives keepalives) {
77             // Noop
78         }
79
80         @Override
81         void configureKeepalives(final Bootstrap bootstrap, final Keepalives keepalives) {
82             // Noop
83         }
84     }
85
86     private static final AbstractSupport SUPPORT;
87
88     static {
89         AbstractSupport support;
90
91         try {
92             support = new Supported();
93         } catch (NoClassDefFoundError e) {
94             LoggerFactory.getLogger(NioNettyImpl.class).warn("Disabling keepalive support", e);
95             support = new Unsupported();
96         }
97
98         SUPPORT = support;
99     }
100
101     static final NioNettyImpl INSTANCE;
102
103     static {
104         final var grp = new NioEventLoopGroup();
105         try {
106             try {
107                 final var ch = new NioSocketChannel();
108                 grp.register(ch).sync();
109
110                 final boolean supportsKeepalives;
111                 try {
112                     supportsKeepalives = SUPPORT.configureKeepalives(ch.config());
113                 } finally {
114                     ch.close().sync();
115                 }
116                 INSTANCE = new NioNettyImpl(supportsKeepalives);
117             } finally {
118                 grp.shutdownGracefully().sync();
119             }
120         } catch (InterruptedException e) {
121             Thread.currentThread().interrupt();
122             throw new ExceptionInInitializerError(e);
123         }
124     }
125
126     private final boolean supportsKeepalives;
127
128     private NioNettyImpl(final boolean supportsKeepalives) {
129         this.supportsKeepalives = supportsKeepalives;
130     }
131
132     @Override
133     Class<NioSocketChannel> channelClass() {
134         return NioSocketChannel.class;
135     }
136
137     @Override
138     Class<NioServerSocketChannel> serverChannelClass() {
139         return NioServerSocketChannel.class;
140     }
141
142     @Override
143     EventLoopGroup newEventLoopGroup(final int numThreads, final ThreadFactory threadFactory) {
144         return new NioEventLoopGroup(numThreads, threadFactory);
145     }
146
147     @Override
148     boolean supportsKeepalives() {
149         return supportsKeepalives;
150     }
151
152     @Override
153     void configureKeepalives(final Bootstrap bootstrap, final Keepalives keepalives) {
154         SUPPORT.configureKeepalives(bootstrap.option(ChannelOption.SO_KEEPALIVE, Boolean.TRUE), keepalives);
155     }
156
157     @Override
158     void configureKeepalives(final ServerBootstrap bootstrap, final Keepalives keepalives) {
159         SUPPORT.configureKeepalives(bootstrap.childOption(ChannelOption.SO_KEEPALIVE, Boolean.TRUE), keepalives);
160     }
161
162     @Override
163     public String toString() {
164         return "java.nio";
165     }
166 }