Add SwitchCertificate attributes in TLS failure notification
[openflowplugin.git] / openflowjava / openflow-protocol-impl / src / main / java / org / opendaylight / openflowjava / protocol / impl / core / TcpChannelInitializer.java
1 /*
2  * Copyright (c) 2013 Pantheon Technologies s.r.o. 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
9 package org.opendaylight.openflowjava.protocol.impl.core;
10
11 import io.netty.channel.Channel;
12 import io.netty.channel.group.DefaultChannelGroup;
13 import io.netty.channel.socket.SocketChannel;
14 import io.netty.handler.ssl.SslHandler;
15 import io.netty.util.concurrent.Future;
16 import java.net.InetAddress;
17 import java.util.Arrays;
18 import java.util.Iterator;
19 import java.util.List;
20 import java.util.concurrent.TimeUnit;
21 import javax.net.ssl.SSLEngine;
22 import org.opendaylight.openflowjava.protocol.impl.core.connection.ConnectionAdapterFactory;
23 import org.opendaylight.openflowjava.protocol.impl.core.connection.ConnectionAdapterFactoryImpl;
24 import org.opendaylight.openflowjava.protocol.impl.core.connection.ConnectionFacade;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
27
28 /**
29  * Initializes TCP / TLS channel.
30  * @author michal.polkorab
31  */
32 public class TcpChannelInitializer extends ProtocolChannelInitializer<SocketChannel> {
33
34     private static final Logger LOG = LoggerFactory.getLogger(TcpChannelInitializer.class);
35     private final DefaultChannelGroup allChannels;
36     private final ConnectionAdapterFactory connectionAdapterFactory;
37
38     /**
39      * Default constructor.
40      */
41     public TcpChannelInitializer() {
42         this(new DefaultChannelGroup("netty-receiver", null), new ConnectionAdapterFactoryImpl());
43     }
44
45     /**
46      * Testing constructor.
47      */
48     protected TcpChannelInitializer(final DefaultChannelGroup channelGroup,
49             final ConnectionAdapterFactory connAdaptorFactory) {
50         allChannels = channelGroup;
51         connectionAdapterFactory = connAdaptorFactory;
52     }
53
54     @Override
55     @SuppressWarnings("checkstyle:IllegalCatch")
56     protected void initChannel(final SocketChannel ch) {
57         if (ch.remoteAddress() != null) {
58             final InetAddress switchAddress = ch.remoteAddress().getAddress();
59             final int port = ch.localAddress().getPort();
60             final int remotePort = ch.remoteAddress().getPort();
61             LOG.debug("Incoming connection from (remote address): {}:{} --> :{}",
62                 switchAddress.toString(), remotePort, port);
63
64             if (!getSwitchConnectionHandler().accept(switchAddress)) {
65                 ch.disconnect();
66                 LOG.debug("Incoming connection rejected");
67                 return;
68             }
69         }
70         LOG.debug("Incoming connection accepted - building pipeline");
71         allChannels.add(ch);
72         ConnectionFacade connectionFacade = null;
73         connectionFacade = connectionAdapterFactory.createConnectionFacade(ch, null, useBarrier(),
74                 getChannelOutboundQueueSize());
75         try {
76             LOG.debug("Calling OF plugin: {}", getSwitchConnectionHandler());
77             getSwitchConnectionHandler().onSwitchConnected(connectionFacade);
78             connectionFacade.checkListeners();
79             boolean tlsPresent = false;
80
81             // If this channel is configured to support SSL it will only support SSL
82             if (getTlsConfiguration() != null) {
83                 tlsPresent = true;
84                 final SslContextFactory sslFactory = new SslContextFactory(getTlsConfiguration());
85                 final SSLEngine engine = sslFactory.getServerContext().createSSLEngine();
86                 engine.setNeedClientAuth(true);
87                 engine.setUseClientMode(false);
88                 List<String> suitesList = getTlsConfiguration().getCipherSuites();
89                 if (suitesList != null && !suitesList.isEmpty()) {
90                     LOG.debug("Requested Cipher Suites are: {}", suitesList);
91                     String[] suites = suitesList.toArray(new String[suitesList.size()]);
92                     engine.setEnabledCipherSuites(suites);
93                     LOG.debug("Cipher suites enabled in SSLEngine are: {}",
94                             Arrays.toString(engine.getEnabledCipherSuites()));
95                 }
96                 final SslHandler ssl = new SslHandler(engine);
97                 final Future<Channel> handshakeFuture = ssl.handshakeFuture();
98                 final ConnectionFacade finalConnectionFacade = connectionFacade;
99                 if (sslFactory.isCustomTrustManagerEnabled()) {
100                     handshakeFuture.addListener(future -> finalConnectionFacade
101                             .onSwitchCertificateIdentified(sslFactory.getSwitchCertificate()));
102                 }
103                 handshakeFuture.addListener(future -> finalConnectionFacade.fireConnectionReadyNotification());
104                 ch.pipeline().addLast(PipelineHandlers.SSL_HANDLER.name(), ssl);
105             }
106             ch.pipeline().addLast(PipelineHandlers.OF_FRAME_DECODER.name(),
107                     new OFFrameDecoder(connectionFacade, tlsPresent));
108             ch.pipeline().addLast(PipelineHandlers.OF_VERSION_DETECTOR.name(), new OFVersionDetector());
109             final OFDecoder ofDecoder = new OFDecoder();
110             ofDecoder.setDeserializationFactory(getDeserializationFactory());
111             ch.pipeline().addLast(PipelineHandlers.OF_DECODER.name(), ofDecoder);
112             final OFEncoder ofEncoder = new OFEncoder();
113             ofEncoder.setSerializationFactory(getSerializationFactory());
114             ch.pipeline().addLast(PipelineHandlers.OF_ENCODER.name(), ofEncoder);
115             ch.pipeline().addLast(PipelineHandlers.IDLE_HANDLER.name(),
116                     new IdleHandler(getSwitchIdleTimeout(), TimeUnit.MILLISECONDS));
117             ch.pipeline().addLast(PipelineHandlers.DELEGATING_INBOUND_HANDLER.name(),
118                     new DelegatingInboundHandler(connectionFacade));
119
120             if (!tlsPresent) {
121                 connectionFacade.fireConnectionReadyNotification();
122             }
123         } catch (RuntimeException e) {
124             LOG.warn("Failed to initialize channel", e);
125             ch.close();
126         }
127     }
128
129     /**
130      * Returns the connection iterator.
131      *
132      * @return iterator through active connections
133      */
134     public Iterator<Channel> getConnectionIterator() {
135         return allChannels.iterator();
136     }
137
138     /**
139      * Returns the number of active channels.
140      *
141      * @return amount of active channels
142      */
143     public int size() {
144         return allChannels.size();
145     }
146 }