Merge "Bug 1073: Added Transaction Chain support to InMemoryDataTreeModification."
[controller.git] / opendaylight / netconf / netconf-ssh / src / main / java / org / opendaylight / controller / netconf / ssh / NetconfSSHServer.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. 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.controller.netconf.ssh;
9
10 import io.netty.channel.EventLoopGroup;
11 import io.netty.channel.local.LocalAddress;
12 import java.io.IOException;
13 import java.net.ServerSocket;
14 import java.net.Socket;
15 import java.util.concurrent.ExecutorService;
16 import java.util.concurrent.Executors;
17 import java.util.concurrent.atomic.AtomicLong;
18 import javax.annotation.concurrent.ThreadSafe;
19 import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
20 import org.opendaylight.controller.netconf.ssh.threads.Handshaker;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23
24 /**
25  * Thread that accepts client connections. Accepted socket is forwarded to {@link org.opendaylight.controller.netconf.ssh.threads.Handshaker},
26  * which is executed in {@link #handshakeExecutor}.
27  */
28 @ThreadSafe
29 public final class NetconfSSHServer extends Thread implements AutoCloseable {
30
31     private static final Logger logger = LoggerFactory.getLogger(NetconfSSHServer.class);
32     private static final AtomicLong sessionIdCounter = new AtomicLong();
33
34     private final ServerSocket serverSocket;
35     private final LocalAddress localAddress;
36     private final EventLoopGroup bossGroup;
37     private final AuthProvider authProvider;
38     private final ExecutorService handshakeExecutor;
39     private volatile boolean up;
40
41     private NetconfSSHServer(int serverPort, LocalAddress localAddress, AuthProvider authProvider, EventLoopGroup bossGroup) throws IOException {
42         super(NetconfSSHServer.class.getSimpleName());
43         this.bossGroup = bossGroup;
44         logger.trace("Creating SSH server socket on port {}", serverPort);
45         this.serverSocket = new ServerSocket(serverPort);
46         if (serverSocket.isBound() == false) {
47             throw new IllegalStateException("Socket can't be bound to requested port :" + serverPort);
48         }
49         logger.trace("Server socket created.");
50         this.localAddress = localAddress;
51         this.authProvider = authProvider;
52         this.up = true;
53         handshakeExecutor = Executors.newFixedThreadPool(10);
54     }
55
56     public static NetconfSSHServer start(int serverPort, LocalAddress localAddress, AuthProvider authProvider, EventLoopGroup bossGroup) throws IOException {
57         NetconfSSHServer netconfSSHServer = new NetconfSSHServer(serverPort, localAddress, authProvider, bossGroup);
58         netconfSSHServer.start();
59         return netconfSSHServer;
60     }
61
62     @Override
63     public void close() throws IOException {
64         up = false;
65         logger.trace("Closing SSH server socket.");
66         serverSocket.close();
67         bossGroup.shutdownGracefully();
68         logger.trace("SSH server socket closed.");
69     }
70
71     @Override
72     public void run() {
73         while (up) {
74             Socket acceptedSocket = null;
75             try {
76                 acceptedSocket = serverSocket.accept();
77             } catch (IOException e) {
78                 if (up == false) {
79                     logger.trace("Exiting server thread", e);
80                 } else {
81                     logger.warn("Exception occurred during socket.accept", e);
82                 }
83             }
84             if (acceptedSocket != null) {
85                 try {
86                     Handshaker task = new Handshaker(acceptedSocket, localAddress, sessionIdCounter.incrementAndGet(), authProvider, bossGroup);
87                     handshakeExecutor.submit(task);
88                 } catch (IOException e) {
89                     logger.warn("Cannot set PEMHostKey, closing connection", e);
90                     try {
91                         acceptedSocket.close();
92                     } catch (IOException e1) {
93                         logger.warn("Ignoring exception while closing socket", e);
94                     }
95                 }
96             }
97         }
98         logger.debug("Server thread is exiting");
99     }
100 }