2 * Copyright (c) 2013 Cisco Systems, Inc. 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.controller.netconf.ssh;
10 import com.google.common.annotations.VisibleForTesting;
11 import io.netty.channel.EventLoopGroup;
12 import io.netty.channel.local.LocalAddress;
13 import java.io.IOException;
14 import java.net.InetSocketAddress;
15 import java.net.ServerSocket;
16 import java.net.Socket;
17 import java.util.concurrent.ExecutorService;
18 import java.util.concurrent.Executors;
19 import java.util.concurrent.atomic.AtomicLong;
20 import javax.annotation.concurrent.ThreadSafe;
21 import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
22 import org.opendaylight.controller.netconf.ssh.threads.Handshaker;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
27 * Thread that accepts client connections. Accepted socket is forwarded to {@link org.opendaylight.controller.netconf.ssh.threads.Handshaker},
28 * which is executed in {@link #handshakeExecutor}.
31 public final class NetconfSSHServer extends Thread implements AutoCloseable {
33 private static final Logger logger = LoggerFactory.getLogger(NetconfSSHServer.class);
34 private static final AtomicLong sessionIdCounter = new AtomicLong();
36 private final ServerSocket serverSocket;
37 private final LocalAddress localAddress;
38 private final EventLoopGroup bossGroup;
39 private final AuthProvider authProvider;
40 private final ExecutorService handshakeExecutor;
41 private volatile boolean up;
43 private NetconfSSHServer(int serverPort, LocalAddress localAddress, AuthProvider authProvider, EventLoopGroup bossGroup) throws IOException {
44 super(NetconfSSHServer.class.getSimpleName());
45 this.bossGroup = bossGroup;
46 logger.trace("Creating SSH server socket on port {}", serverPort);
47 this.serverSocket = new ServerSocket(serverPort);
48 if (serverSocket.isBound() == false) {
49 throw new IllegalStateException("Socket can't be bound to requested port :" + serverPort);
51 logger.trace("Server socket created.");
52 this.localAddress = localAddress;
53 this.authProvider = authProvider;
55 handshakeExecutor = Executors.newFixedThreadPool(10);
58 public static NetconfSSHServer start(int serverPort, LocalAddress localAddress, AuthProvider authProvider, EventLoopGroup bossGroup) throws IOException {
59 NetconfSSHServer netconfSSHServer = new NetconfSSHServer(serverPort, localAddress, authProvider, bossGroup);
60 netconfSSHServer.start();
61 return netconfSSHServer;
65 public void close() throws IOException {
67 logger.trace("Closing SSH server socket.");
69 bossGroup.shutdownGracefully();
70 logger.trace("SSH server socket closed.");
74 public InetSocketAddress getLocalSocketAddress() {
75 return (InetSocketAddress) serverSocket.getLocalSocketAddress();
81 Socket acceptedSocket = null;
83 acceptedSocket = serverSocket.accept();
84 } catch (IOException e) {
86 logger.trace("Exiting server thread", e);
88 logger.warn("Exception occurred during socket.accept", e);
91 if (acceptedSocket != null) {
93 Handshaker task = new Handshaker(acceptedSocket, localAddress, sessionIdCounter.incrementAndGet(), authProvider, bossGroup);
94 handshakeExecutor.submit(task);
95 } catch (IOException e) {
96 logger.warn("Cannot set PEMHostKey, closing connection", e);
98 acceptedSocket.close();
99 } catch (IOException e1) {
100 logger.warn("Ignoring exception while closing socket", e);
105 logger.debug("Server thread is exiting");