4fccee7566f3abb10888fdc8aed5c9fccc515005
[netconf.git] / netconf / callhome-server / src / main / java / org / opendaylight / netconf / callhome / server / tls / CallHomeTlsServer.java
1 /*
2  * Copyright (c) 2023 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.callhome.server.tls;
9
10 import static java.util.Objects.requireNonNull;
11
12 import io.netty.channel.ChannelOption;
13 import java.net.InetAddress;
14 import java.util.concurrent.ExecutionException;
15 import java.util.concurrent.TimeUnit;
16 import java.util.concurrent.TimeoutException;
17 import org.eclipse.jdt.annotation.NonNull;
18 import org.opendaylight.netconf.callhome.server.CallHomeStatusRecorder;
19 import org.opendaylight.netconf.callhome.server.CallHomeTransportChannelListener;
20 import org.opendaylight.netconf.client.NetconfClientSessionNegotiatorFactory;
21 import org.opendaylight.netconf.transport.api.UnsupportedConfigurationException;
22 import org.opendaylight.netconf.transport.tcp.BootstrapFactory;
23 import org.opendaylight.netconf.transport.tls.TLSClient;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.client.rev231228.netconf.client.listen.stack.grouping.transport.ssh.ssh.TcpServerParametersBuilder;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tcp.server.rev231228.TcpServerGrouping;
28 import org.opendaylight.yangtools.yang.common.Uint16;
29
30 public final class CallHomeTlsServer implements AutoCloseable {
31     private static final int DEFAULT_PORT = 4335;
32     private static final Integer DEFAULT_TIMEOUT_MILLIS = 5000;
33     private static final Integer DEFAULT_MAX_CONNECTIONS = 64;
34
35     private final CallHomeTlsSessionContextManager contextManager;
36     private final TLSClient client;
37
38     private CallHomeTlsServer(final TcpServerGrouping tcpServerParams,
39             final BootstrapFactory bootstrapFactory,
40             final Integer maxConnections, final Integer timeoutMillis,
41             final NetconfClientSessionNegotiatorFactory negotiationFactory,
42             final CallHomeTlsSessionContextManager contextManager,
43             final CallHomeTlsAuthProvider authProvider,
44             final CallHomeStatusRecorder statusRecorder) {
45         this.contextManager = requireNonNull(contextManager);
46         final var bootstrap = bootstrapFactory.newServerBootstrap()
47             .childOption(ChannelOption.SO_KEEPALIVE, true)
48             .childOption(ChannelOption.SO_BACKLOG, requireNonNull(maxConnections))
49             .childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, requireNonNull(timeoutMillis));
50         final var transportChannelListener = new CallHomeTransportChannelListener(requireNonNull(negotiationFactory),
51             contextManager, requireNonNull(statusRecorder));
52         try {
53             client = TLSClient.listen(transportChannelListener, bootstrap, tcpServerParams, authProvider)
54                 .get(timeoutMillis, TimeUnit.MILLISECONDS);
55         } catch (UnsupportedConfigurationException | InterruptedException | ExecutionException | TimeoutException e) {
56             throw new IllegalStateException("Could not start TLS Call-Home server", e);
57         }
58     }
59
60     @Override
61     public void close() throws Exception {
62         contextManager.close();
63         client.shutdown().get();
64     }
65
66     public static Builder builder() {
67         return new Builder();
68     }
69
70     public static final class Builder {
71
72         private InetAddress address;
73         private int port = DEFAULT_PORT;
74         private BootstrapFactory bootstrapFactory;
75         private NetconfClientSessionNegotiatorFactory negotiationFactory;
76         private Integer maxConnections;
77         private Integer timeoutMillis;
78         private CallHomeTlsAuthProvider authProvider;
79         private CallHomeTlsSessionContextManager contextManager;
80         private CallHomeStatusRecorder statusRecorder;
81
82         private Builder() {
83             // on purpose
84         }
85
86         public @NonNull CallHomeTlsServer build() {
87             return new CallHomeTlsServer(
88                 toServerParams(address, port),
89                 bootstrapFactory == null ? defaultBootstrapFactory() : bootstrapFactory,
90                 maxConnections == null ? DEFAULT_MAX_CONNECTIONS : maxConnections,
91                 timeoutMillis == null ? DEFAULT_TIMEOUT_MILLIS : timeoutMillis,
92                 negotiationFactory, contextManager, authProvider, statusRecorder);
93         }
94
95         public Builder withSessionContextManager(final CallHomeTlsSessionContextManager newContextManager) {
96             contextManager = newContextManager;
97             return this;
98         }
99
100         public Builder withAuthProvider(final CallHomeTlsAuthProvider newAuthProvider) {
101             authProvider = newAuthProvider;
102             return this;
103         }
104
105         public Builder withStatusRecorder(final CallHomeStatusRecorder newStatusRecorder) {
106             statusRecorder = newStatusRecorder;
107             return this;
108         }
109
110         public Builder withAddress(final InetAddress newAddress) {
111             address = newAddress;
112             return this;
113         }
114
115         public Builder withPort(final int newPort) {
116             port = newPort;
117             return this;
118         }
119
120         public Builder withMaxConnections(final int newMaxConnections) {
121             maxConnections = newMaxConnections;
122             return this;
123         }
124
125         public Builder withTimeout(final int newTimeoutMillis) {
126             timeoutMillis = newTimeoutMillis;
127             return this;
128         }
129
130         public Builder withBootstrapFactory(final BootstrapFactory newBootstrapFactory) {
131             bootstrapFactory = newBootstrapFactory;
132             return this;
133         }
134
135         public Builder withNegotiationFactory(final NetconfClientSessionNegotiatorFactory newNegotiationFactory) {
136             negotiationFactory = newNegotiationFactory;
137             return this;
138         }
139     }
140
141     private static TcpServerGrouping toServerParams(final InetAddress address, final int port) {
142         final var ipAddress = IetfInetUtil.ipAddressFor(
143             address == null ? InetAddress.getLoopbackAddress() : address);
144         final var portNumber = new PortNumber(Uint16.valueOf(port < 0 ? DEFAULT_PORT : port));
145         return new TcpServerParametersBuilder().setLocalAddress(ipAddress).setLocalPort(portNumber).build();
146     }
147
148     private static BootstrapFactory defaultBootstrapFactory() {
149         return new BootstrapFactory("tls-call-home-server", 0);
150     }
151 }