2 * Copyright (c) 2023 PANTHEON.tech s.r.o. and others. All rights reserved.
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
8 package org.opendaylight.netconf.topology.callhome;
10 import static java.util.Objects.requireNonNull;
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.client.NetconfClientSessionNegotiatorFactory;
19 import org.opendaylight.netconf.transport.api.UnsupportedConfigurationException;
20 import org.opendaylight.netconf.transport.tcp.BootstrapFactory;
21 import org.opendaylight.netconf.transport.tls.TLSClient;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
24 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;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tcp.server.rev231228.TcpServerGrouping;
26 import org.opendaylight.yangtools.yang.common.Uint16;
28 public final class CallHomeTlsServer implements AutoCloseable {
29 private static final int DEFAULT_PORT = 4335;
30 private static final Integer DEFAULT_TIMEOUT_MILLIS = 5000;
31 private static final Integer DEFAULT_MAX_CONNECTIONS = 64;
33 private final CallHomeTlsSessionContextManager contextManager;
34 private final TLSClient client;
36 private CallHomeTlsServer(final TcpServerGrouping tcpServerParams,
37 final BootstrapFactory bootstrapFactory,
38 final Integer maxConnections, final Integer timeoutMillis,
39 final NetconfClientSessionNegotiatorFactory negotiationFactory,
40 final CallHomeTlsSessionContextManager contextManager,
41 final CallHomeTlsAuthProvider authProvider,
42 final CallHomeStatusRecorder statusRecorder) {
43 this.contextManager = requireNonNull(contextManager);
44 final var bootstrap = bootstrapFactory.newServerBootstrap()
45 .childOption(ChannelOption.SO_KEEPALIVE, true)
46 .childOption(ChannelOption.SO_BACKLOG, requireNonNull(maxConnections))
47 .childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, requireNonNull(timeoutMillis));
48 final var transportChannelListener = new CallHomeTransportChannelListener(requireNonNull(negotiationFactory),
49 contextManager, requireNonNull(statusRecorder));
51 client = TLSClient.listen(transportChannelListener, bootstrap, tcpServerParams, authProvider)
52 .get(timeoutMillis, TimeUnit.MILLISECONDS);
53 } catch (UnsupportedConfigurationException | InterruptedException | ExecutionException | TimeoutException e) {
54 throw new IllegalStateException("Could not start TLS Call-Home server", e);
59 public void close() throws Exception {
60 contextManager.close();
61 client.shutdown().get();
64 public static Builder builder() {
68 public static final class Builder {
70 private InetAddress address;
71 private int port = DEFAULT_PORT;
72 private BootstrapFactory bootstrapFactory;
73 private NetconfClientSessionNegotiatorFactory negotiationFactory;
74 private Integer maxConnections;
75 private Integer timeoutMillis;
76 private CallHomeTlsAuthProvider authProvider;
77 private CallHomeTlsSessionContextManager contextManager;
78 private CallHomeStatusRecorder statusRecorder;
84 public @NonNull CallHomeTlsServer build() {
85 return new CallHomeTlsServer(
86 toServerParams(address, port),
87 bootstrapFactory == null ? defaultBootstrapFactory() : bootstrapFactory,
88 maxConnections == null ? DEFAULT_MAX_CONNECTIONS : maxConnections,
89 timeoutMillis == null ? DEFAULT_TIMEOUT_MILLIS : timeoutMillis,
90 negotiationFactory, contextManager, authProvider, statusRecorder);
93 public Builder withSessionContextManager(final CallHomeTlsSessionContextManager newContextManager) {
94 contextManager = newContextManager;
98 public Builder withAuthProvider(final CallHomeTlsAuthProvider newAuthProvider) {
99 authProvider = newAuthProvider;
103 public Builder withStatusRecorder(final CallHomeStatusRecorder newStatusRecorder) {
104 statusRecorder = newStatusRecorder;
108 public Builder withAddress(final InetAddress newAddress) {
109 address = newAddress;
113 public Builder withPort(final int newPort) {
118 public Builder withMaxConnections(final int newMaxConnections) {
119 maxConnections = newMaxConnections;
123 public Builder withTimeout(final int newTimeoutMillis) {
124 timeoutMillis = newTimeoutMillis;
128 public Builder withBootstrapFactory(final BootstrapFactory newBootstrapFactory) {
129 bootstrapFactory = newBootstrapFactory;
133 public Builder withNegotiationFactory(final NetconfClientSessionNegotiatorFactory newNegotiationFactory) {
134 negotiationFactory = newNegotiationFactory;
139 private static TcpServerGrouping toServerParams(final InetAddress address, final int port) {
140 final var ipAddress = IetfInetUtil.ipAddressFor(
141 address == null ? InetAddress.getLoopbackAddress() : address);
142 final var portNumber = new PortNumber(Uint16.valueOf(port < 0 ? DEFAULT_PORT : port));
143 return new TcpServerParametersBuilder().setLocalAddress(ipAddress).setLocalPort(portNumber).build();
146 private static BootstrapFactory defaultBootstrapFactory() {
147 return new BootstrapFactory("tls-call-home-server", 0);