2 * Copyright (c) 2022 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.transport.tcp;
10 import static com.google.common.base.Verify.verifyNotNull;
11 import static java.util.Objects.requireNonNull;
13 import com.google.common.annotations.VisibleForTesting;
14 import com.google.common.util.concurrent.ListenableFuture;
15 import com.google.common.util.concurrent.SettableFuture;
16 import io.netty.bootstrap.ServerBootstrap;
17 import io.netty.channel.Channel;
18 import io.netty.channel.ChannelFutureListener;
19 import io.netty.channel.ChannelHandler.Sharable;
20 import io.netty.channel.ChannelInitializer;
21 import org.eclipse.jdt.annotation.NonNull;
22 import org.opendaylight.netconf.transport.api.TransportChannelListener;
23 import org.opendaylight.netconf.transport.api.UnsupportedConfigurationException;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.tcp.server.rev231228.TcpServerGrouping;
25 import org.opendaylight.yangtools.yang.common.Empty;
28 * A {@link TCPTransportStack} acting as a TCP server.
30 public final class TCPServer extends TCPTransportStack {
32 private static final class ListenChannelInitializer extends ChannelInitializer<Channel> {
33 private final TCPServer stack;
35 ListenChannelInitializer(final TCPServer stack) {
36 this.stack = requireNonNull(stack);
40 protected void initChannel(final Channel ch) {
41 verifyNotNull(stack, "Stack not initialized while handling channel %s", ch)
42 .addTransportChannel(new TCPTransportChannel(ch));
46 private volatile Channel listenChannel;
48 private TCPServer(final TransportChannelListener listener) {
53 * Attempt to establish a {@link TCPClient} by connecting to a remote address.
55 * @param listener {@link TransportChannelListener} to notify when the session is established
56 * @param bootstrap {@link ServerBootstrap} to use for the underlying Netty server channel
57 * @param listenParams Listening parameters
59 * @throws UnsupportedConfigurationException when {@code listenParams} contains an unsupported options
60 * @throws NullPointerException if any argument is {@code null}
62 public static @NonNull ListenableFuture<TCPServer> listen(final TransportChannelListener listener,
63 final ServerBootstrap bootstrap, final TcpServerGrouping listenParams)
64 throws UnsupportedConfigurationException {
65 NettyTransportSupport.configureKeepalives(bootstrap, listenParams.getKeepalives());
67 final var ret = SettableFuture.<TCPServer>create();
68 final var stack = new TCPServer(listener);
69 final var initializer = new ListenChannelInitializer(stack);
71 .childHandler(initializer)
72 .bind(socketAddressOf(listenParams.requireLocalAddress(), listenParams.requireLocalPort()))
73 .addListener((ChannelFutureListener) future -> {
74 if (future.isSuccess()) {
75 stack.setListenChannel(future.channel());
78 ret.setException(future.cause());
85 protected ListenableFuture<Empty> startShutdown() {
86 return toListenableFuture(listenChannel().close());
90 @NonNull Channel listenChannel() {
91 return verifyNotNull(listenChannel, "Channel not initialized");
94 private void setListenChannel(final Channel listenChannel) {
95 this.listenChannel = requireNonNull(listenChannel);