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.callhome.server.tls;
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.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;
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;
35 private final CallHomeTlsSessionContextManager contextManager;
36 private final TLSClient client;
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));
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);
61 public void close() throws Exception {
62 contextManager.close();
63 client.shutdown().get();
66 public static Builder builder() {
70 public static final class Builder {
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;
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);
95 public Builder withSessionContextManager(final CallHomeTlsSessionContextManager newContextManager) {
96 contextManager = newContextManager;
100 public Builder withAuthProvider(final CallHomeTlsAuthProvider newAuthProvider) {
101 authProvider = newAuthProvider;
105 public Builder withStatusRecorder(final CallHomeStatusRecorder newStatusRecorder) {
106 statusRecorder = newStatusRecorder;
110 public Builder withAddress(final InetAddress newAddress) {
111 address = newAddress;
115 public Builder withPort(final int newPort) {
120 public Builder withMaxConnections(final int newMaxConnections) {
121 maxConnections = newMaxConnections;
125 public Builder withTimeout(final int newTimeoutMillis) {
126 timeoutMillis = newTimeoutMillis;
130 public Builder withBootstrapFactory(final BootstrapFactory newBootstrapFactory) {
131 bootstrapFactory = newBootstrapFactory;
135 public Builder withNegotiationFactory(final NetconfClientSessionNegotiatorFactory newNegotiationFactory) {
136 negotiationFactory = newNegotiationFactory;
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();
148 private static BootstrapFactory defaultBootstrapFactory() {
149 return new BootstrapFactory("tls-call-home-server", 0);