UDP support implementation 32/10432/3
authorMichal Polkorab <michal.polkorab@pantheon.sk>
Thu, 7 Aug 2014 09:54:00 +0000 (11:54 +0200)
committerMichal Polkorab <michal.polkorab@pantheon.sk>
Thu, 28 Aug 2014 12:50:02 +0000 (14:50 +0200)
 - unit tests will be added in another change

Change-Id: I8b6fba59a82febf60c0ddfb97ef8e2e9267aff56
Signed-off-by: Michal Polkorab <michal.polkorab@pantheon.sk>
34 files changed:
openflow-protocol-api/src/main/yang/openflow-configuration.yang
openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/connection/ChannelOutboundQueue.java
openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/connection/ConnectionAdapterFactory.java
openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/connection/ConnectionAdapterFactoryImpl.java
openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/connection/ConnectionAdapterImpl.java
openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/connection/ServerFacade.java
openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/connection/SwitchConnectionProviderImpl.java
openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/connection/UdpMessageListenerWrapper.java [new file with mode: 0644]
openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/ChannelInitializerFactory.java [moved from openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/PublishingChannelInitializerFactory.java with 74% similarity]
openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFDatagramPacketDecoder.java [new file with mode: 0644]
openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFDatagramPacketEncoder.java [new file with mode: 0644]
openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFDatagramPacketHandler.java [new file with mode: 0644]
openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/PipelineHandlers.java [new file with mode: 0644]
openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/ProtocolChannelInitializer.java [new file with mode: 0644]
openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/PublishingChannelInitializer.java [deleted file]
openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/TcpChannelInitializer.java [new file with mode: 0644]
openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/TcpHandler.java
openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/UdpChannelInitializer.java [new file with mode: 0644]
openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/UdpConnectionMap.java [new file with mode: 0644]
openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/UdpHandler.java [new file with mode: 0644]
openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/VersionMessageUdpWrapper.java [new file with mode: 0644]
openflow-protocol-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/openflow/_switch/connection/provider/impl/rev140328/SwitchConnectionProviderModule.java
openflow-protocol-impl/src/main/yang/openflow-switch-connection-provider-impl.yang
openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/PublishingChannelInitializerFactoryTest.java
openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/PublishingChannelInitializerTest.java
openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/TcpHandlerTest.java
openflow-protocol-it/src/test/java/org/opendaylight/openflowjava/protocol/it/integration/ConnectionConfigurationImpl.java
openflow-protocol-it/src/test/java/org/opendaylight/openflowjava/protocol/it/integration/IntegrationTest.java
simple-client/src/main/java/org/opendaylight/openflowjava/protocol/impl/clients/OFClient.java [new file with mode: 0644]
simple-client/src/main/java/org/opendaylight/openflowjava/protocol/impl/clients/SimpleClient.java
simple-client/src/main/java/org/opendaylight/openflowjava/protocol/impl/clients/SimpleClientInitializer.java
simple-client/src/main/java/org/opendaylight/openflowjava/protocol/impl/clients/UdpSimpleClient.java [new file with mode: 0644]
simple-client/src/main/java/org/opendaylight/openflowjava/protocol/impl/clients/UdpSimpleClientFramer.java [new file with mode: 0644]
simple-client/src/main/java/org/opendaylight/openflowjava/protocol/impl/clients/UdpSimpleClientInitializer.java [new file with mode: 0644]

index 36b163cbb101bf77da928c160cdd899786fbd506..8a1f8bbc42d70c810b606a6bb03c9eb53bbdb188 100644 (file)
             }\r
         }\r
     }\r
+\r
+    typedef transport-protocol {\r
+        type enumeration {\r
+            enum TCP {\r
+                value 0;\r
+                description "Communication over TCP protocol.";\r
+            }\r
+            enum TLS {\r
+                value 1;\r
+                description "Communication over TLS protocol.";\r
+            }\r
+            enum UDP {\r
+                value 2;\r
+                description "Communication over UDP protocol.";\r
+            }\r
+        }\r
+    }\r
 }
\ No newline at end of file
index 40af2791407451c89f8e7d75debc95055cf77733..6937a1fb004e8c2d1ed02ec0470813593e748300 100644 (file)
@@ -16,6 +16,7 @@ import io.netty.util.concurrent.EventExecutor;
 import io.netty.util.concurrent.Future;
 import io.netty.util.concurrent.GenericFutureListener;
 
+import java.net.InetSocketAddress;
 import java.util.Queue;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.RejectedExecutionException;
@@ -95,6 +96,7 @@ final class ChannelOutboundQueue extends ChannelInboundHandlerAdapter {
     private final Queue<MessageHolder<?>> queue;
     private final long maxWorkTime;
     private final Channel channel;
+    private InetSocketAddress address;
 
     public ChannelOutboundQueue(final Channel channel, final int queueDepth) {
         Preconditions.checkArgument(queueDepth > 0, "Queue depth has to be positive");
@@ -181,7 +183,13 @@ final class ChannelOutboundQueue extends ChannelInboundHandlerAdapter {
             }
 
             final GenericFutureListener<Future<Void>> l = h.takeListener();
-            final ChannelFuture p = channel.write(new MessageListenerWrapper(h.takeMessage(), l));
+            
+            final ChannelFuture p;
+            if (address == null) {
+                p = channel.write(new MessageListenerWrapper(h.takeMessage(), l));
+            } else {
+                p = channel.write(new UdpMessageListenerWrapper(h.takeMessage(), l, address));
+            }
             if (l != null) {
                 p.addListener(l);
             }
@@ -268,4 +276,8 @@ final class ChannelOutboundQueue extends ChannelInboundHandlerAdapter {
     public String toString() {
         return String.format("Channel %s queue [%s messages flushing=%s]", channel, queue.size(), flushScheduled);
     }
+
+    public void setAddress(InetSocketAddress address) {
+        this.address = address;
+    }
 }
index 3070aba83ecd73550f65de7a09c7e23e02379c39..dba298b7dba917c924ece38674809dc11f1be85a 100644 (file)
@@ -9,7 +9,9 @@
 
 package org.opendaylight.openflowjava.protocol.impl.connection;
 
-import io.netty.channel.socket.SocketChannel;
+import java.net.InetSocketAddress;
+
+import io.netty.channel.Channel;
 
 /**
  * @author mirehak
@@ -21,6 +23,6 @@ public interface ConnectionAdapterFactory {
      * @param ch
      * @return connection adapter tcp-implementation
      */
-    public ConnectionFacade createConnectionFacade(SocketChannel ch) ;
+    public ConnectionFacade createConnectionFacade(Channel ch, InetSocketAddress address) ;
 
 }
index fda222cec52cb37c884ff8b5b5b7ba633164f402..259dd6f571bca5905289da303ce84cc2f54f7626 100644 (file)
@@ -9,7 +9,9 @@
 
 package org.opendaylight.openflowjava.protocol.impl.connection;
 
-import io.netty.channel.socket.SocketChannel;
+import java.net.InetSocketAddress;
+
+import io.netty.channel.Channel;
 
 /**
  * @author mirehak
@@ -22,8 +24,8 @@ public class ConnectionAdapterFactoryImpl implements ConnectionAdapterFactory {
      * @return connection adapter tcp-implementation
      */
        @Override
-    public ConnectionFacade createConnectionFacade(SocketChannel ch) {
-        return new ConnectionAdapterImpl(ch);
+    public ConnectionFacade createConnectionFacade(Channel ch, InetSocketAddress address) {
+        return new ConnectionAdapterImpl(ch, address);
     }
 
 }
index 44595d7c2f1d85113cfba53e135deeadc8aeb95f..9fe040fcc4fbb630966a21f45ec8949e030a7bf2 100644 (file)
@@ -9,8 +9,8 @@
 
 package org.opendaylight.openflowjava.protocol.impl.connection;
 
+import io.netty.channel.Channel;
 import io.netty.channel.ChannelFuture;
-import io.netty.channel.socket.SocketChannel;
 import io.netty.util.concurrent.GenericFutureListener;
 
 import java.net.InetSocketAddress;
@@ -111,7 +111,7 @@ public class ConnectionAdapterImpl implements ConnectionFacade {
     private final Cache<RpcResponseKey, ResponseExpectedRpcListener<?>> responseCache;
 
     private final ChannelOutboundQueue output;
-    private final SocketChannel channel;
+    private final Channel channel;
 
     private ConnectionReadyListener connectionReadyListener;
     private OpenflowProtocolListener messageListener;
@@ -121,14 +121,17 @@ public class ConnectionAdapterImpl implements ConnectionFacade {
     /**
      * default ctor
      * @param channel the channel to be set - used for communication
+     * @param address client address (used only in case of UDP communication,
+     *  as there is no need to store address over tcp (stable channel))
      */
-    public ConnectionAdapterImpl(final SocketChannel channel) {
+    public ConnectionAdapterImpl(final Channel channel, final InetSocketAddress address) {
         responseCache = CacheBuilder.newBuilder()
                 .concurrencyLevel(1)
                 .expireAfterWrite(RPC_RESPONSE_EXPIRATION, TimeUnit.MINUTES)
                 .removalListener(REMOVAL_LISTENER).build();
         this.channel = Preconditions.checkNotNull(channel);
         this.output = new ChannelOutboundQueue(channel, DEFAULT_QUEUE_DEPTH);
+        output.setAddress(address);
         channel.pipeline().addLast(output);
         LOG.debug("ConnectionAdapter created");
     }
@@ -471,6 +474,6 @@ public class ConnectionAdapterImpl implements ConnectionFacade {
 
     @Override
     public InetSocketAddress getRemoteAddress() {
-        return channel.remoteAddress();
+        return (InetSocketAddress) channel.remoteAddress();
     }
 }
index 84c84df724f71a88a63f999ac618f033c1175921..39a6eb7ef3654bf02fdd2a6fed5d10c3d213312b 100644 (file)
@@ -9,10 +9,16 @@
 
 package org.opendaylight.openflowjava.protocol.impl.connection;
 
+import org.opendaylight.openflowjava.protocol.api.connection.ThreadConfiguration;
+
 /**
  * @author mirehak
  */
 public interface ServerFacade extends ShutdownProvider, OnlineProvider, Runnable {
 
-    // empty unifying superinterface
+    /**
+     * Sets thread configuration
+     * @param threadConfig desired thread configuration
+     */
+    public void setThreadConfig(ThreadConfiguration threadConfig);
 }
index b3785de612b7e48965b71fba09e899c877eac273..d8c38cd5c08d221f216f8e9b067721a4f182ceb8 100644 (file)
@@ -25,13 +25,15 @@ import org.opendaylight.openflowjava.protocol.api.keys.experimenter.Experimenter
 import org.opendaylight.openflowjava.protocol.api.keys.experimenter.ExperimenterInstructionDeserializerKey;
 import org.opendaylight.openflowjava.protocol.api.keys.experimenter.ExperimenterInstructionSerializerKey;
 import org.opendaylight.openflowjava.protocol.api.keys.experimenter.ExperimenterSerializerKey;
-import org.opendaylight.openflowjava.protocol.impl.core.PublishingChannelInitializerFactory;
+import org.opendaylight.openflowjava.protocol.impl.core.ChannelInitializerFactory;
 import org.opendaylight.openflowjava.protocol.impl.core.TcpHandler;
+import org.opendaylight.openflowjava.protocol.impl.core.UdpHandler;
 import org.opendaylight.openflowjava.protocol.impl.deserialization.DeserializationFactory;
 import org.opendaylight.openflowjava.protocol.impl.deserialization.DeserializerRegistryImpl;
 import org.opendaylight.openflowjava.protocol.impl.serialization.SerializationFactory;
 import org.opendaylight.openflowjava.protocol.impl.serialization.SerializerRegistryImpl;
 import org.opendaylight.openflowjava.protocol.spi.connection.SwitchConnectionProvider;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.TransportProtocol;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.MatchField;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.OxmClassBase;
 import org.slf4j.Logger;
@@ -118,16 +120,23 @@ public class SwitchConnectionProviderImpl implements SwitchConnectionProvider {
     /**
      * @return
      */
-    private TcpHandler createAndConfigureServer() {
+    private ServerFacade createAndConfigureServer() {
         LOGGER.debug("Configuring ..");
-        TcpHandler server = new TcpHandler(connConfig.getAddress(), connConfig.getPort());
-        PublishingChannelInitializerFactory factory = new PublishingChannelInitializerFactory();
+        ServerFacade server = null;
+        ChannelInitializerFactory factory = new ChannelInitializerFactory();
         factory.setSwitchConnectionHandler(switchConnectionHandler);
         factory.setSwitchIdleTimeout(connConfig.getSwitchIdleTimeout());
         factory.setTlsConfig(connConfig.getTlsConfiguration());
         factory.setSerializationFactory(serializationFactory);
         factory.setDeserializationFactory(deserializationFactory);
-        server.setChannelInitializer(factory.createPublishingChannelInitializer());
+        TransportProtocol transportProtocol = (TransportProtocol) connConfig.getTransferProtocol();
+        if (transportProtocol.equals(TransportProtocol.TCP) || transportProtocol.equals(TransportProtocol.TLS)) {
+            server = new TcpHandler(connConfig.getAddress(), connConfig.getPort());
+            ((TcpHandler) server).setChannelInitializer(factory.createPublishingChannelInitializer());
+        } else {
+            server = new UdpHandler(connConfig.getAddress(), connConfig.getPort());
+            ((UdpHandler) server).setChannelInitializer(factory.createUdpChannelInitializer());
+        }
         server.setThreadConfig(connConfig.getThreadConfiguration());
         return server;
     }
diff --git a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/connection/UdpMessageListenerWrapper.java b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/connection/UdpMessageListenerWrapper.java
new file mode 100644 (file)
index 0000000..84bf0b1
--- /dev/null
@@ -0,0 +1,45 @@
+/*\r
+ * Copyright (c) 2014 Pantheon Technologies s.r.o. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.openflowjava.protocol.impl.connection;\r
+\r
+import io.netty.util.concurrent.Future;\r
+import io.netty.util.concurrent.GenericFutureListener;\r
+\r
+import java.net.InetSocketAddress;\r
+\r
+/**\r
+ * Wraps outgoing message and includes listener attached to this message. This object\r
+ * is sent to OFEncoder. When OFEncoder fails to serialize the message,\r
+ * listener is filled with exception. The exception is then delegated to upper ODL layers.\r
+ * This object is used for UDP communication - it also carries recipient address\r
\r
+ * @author michal.polkorab\r
+ */\r
+public class UdpMessageListenerWrapper extends MessageListenerWrapper {\r
+\r
+    private InetSocketAddress address;\r
+\r
+    /**\r
+     * @param msg message to be sent\r
+     * @param listener listener attached to channel.write(msg) Future\r
+     * @param address recipient's address\r
+     */\r
+    public UdpMessageListenerWrapper(Object msg, GenericFutureListener<Future<Void>> listener,\r
+            InetSocketAddress address) {\r
+        super(msg, listener);\r
+        this.address = address;\r
+    }\r
+\r
+    /**\r
+     * @return recipient address\r
+     */\r
+    public InetSocketAddress getAddress() {\r
+        return address;\r
+    }\r
+}
\ No newline at end of file
@@ -17,7 +17,7 @@ import org.opendaylight.openflowjava.protocol.impl.serialization.SerializationFa
  * @author michal.polkorab\r
  *\r
  */\r
-public class PublishingChannelInitializerFactory {\r
+public class ChannelInitializerFactory {\r
 \r
     private long switchIdleTimeOut;\r
     private DeserializationFactory deserializationFactory;\r
@@ -28,8 +28,8 @@ public class PublishingChannelInitializerFactory {
     /**\r
      * @return PublishingChannelInitializer that initializes new channels\r
      */\r
-    public PublishingChannelInitializer createPublishingChannelInitializer() {\r
-        PublishingChannelInitializer initializer = new PublishingChannelInitializer();\r
+    public TcpChannelInitializer createPublishingChannelInitializer() {\r
+        TcpChannelInitializer initializer = new TcpChannelInitializer();\r
         initializer.setSwitchIdleTimeout(switchIdleTimeOut);\r
         initializer.setDeserializationFactory(deserializationFactory);\r
         initializer.setSerializationFactory(serializationFactory);\r
@@ -38,6 +38,18 @@ public class PublishingChannelInitializerFactory {
         return initializer;\r
     }\r
 \r
+    /**\r
+     * @return PublishingChannelInitializer that initializes new channels\r
+     */\r
+    public UdpChannelInitializer createUdpChannelInitializer() {\r
+        UdpChannelInitializer initializer = new UdpChannelInitializer();\r
+        initializer.setSwitchIdleTimeout(switchIdleTimeOut);\r
+        initializer.setDeserializationFactory(deserializationFactory);\r
+        initializer.setSerializationFactory(serializationFactory);\r
+        initializer.setSwitchConnectionHandler(switchConnectionHandler);\r
+        return initializer;\r
+    }\r
+\r
     /**\r
      * @param switchIdleTimeOut\r
      */\r
@@ -72,6 +84,4 @@ public class PublishingChannelInitializerFactory {
     public void setSwitchConnectionHandler(SwitchConnectionHandler switchConnectionHandler) {\r
         this.switchConnectionHandler = switchConnectionHandler;\r
     }\r
-\r
-    \r
-}\r
+}
\ No newline at end of file
diff --git a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFDatagramPacketDecoder.java b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFDatagramPacketDecoder.java
new file mode 100644 (file)
index 0000000..7b4c318
--- /dev/null
@@ -0,0 +1,67 @@
+/*\r
+ * Copyright (c) 2014 Pantheon Technologies s.r.o. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.openflowjava.protocol.impl.core;\r
+\r
+import io.netty.channel.ChannelHandlerContext;\r
+import io.netty.handler.codec.MessageToMessageDecoder;\r
+\r
+import java.util.List;\r
+\r
+import org.opendaylight.openflowjava.protocol.impl.connection.MessageConsumer;\r
+import org.opendaylight.openflowjava.protocol.impl.deserialization.DeserializationFactory;\r
+import org.opendaylight.openflowjava.util.ByteBufUtils;\r
+import org.opendaylight.yangtools.yang.binding.DataObject;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+\r
+/**\r
+ * @author michal.polkorab\r
+ *\r
+ */\r
+public class OFDatagramPacketDecoder extends MessageToMessageDecoder<VersionMessageUdpWrapper>{\r
+\r
+    private static final Logger LOGGER = LoggerFactory.getLogger(OFDatagramPacketDecoder.class);\r
+    private DeserializationFactory deserializationFactory;\r
+\r
+    @Override\r
+    protected void decode(ChannelHandlerContext ctx,\r
+            VersionMessageUdpWrapper msg, List<Object> out) throws Exception {\r
+        if (LOGGER.isDebugEnabled()) {\r
+            LOGGER.debug("UdpVersionMessageWrapper received");\r
+            LOGGER.debug("<< " + ByteBufUtils.byteBufToHexString(msg.getMessageBuffer()));\r
+        }\r
+\r
+        DataObject dataObject = null;\r
+        try {\r
+            dataObject = deserializationFactory.deserialize(msg.getMessageBuffer(),\r
+                    msg.getVersion());\r
+            if (dataObject == null) {\r
+                LOGGER.warn("Translated POJO is null");\r
+            } else {\r
+                MessageConsumer consumer = UdpConnectionMap.getMessageConsumer(msg.getAddress());\r
+                consumer.consume(dataObject);\r
+            }\r
+        } catch(Exception e) {\r
+            LOGGER.error("Message deserialization failed");\r
+            LOGGER.error(e.getMessage(), e);\r
+            // TODO: delegate exception to allow easier deserialization\r
+            // debugging / deserialization problem awareness\r
+        } finally {\r
+            msg.getMessageBuffer().release();\r
+        }\r
+        \r
+    }\r
+\r
+    /**\r
+     * @param deserializationFactory\r
+     */\r
+    public void setDeserializationFactory(DeserializationFactory deserializationFactory) {\r
+        this.deserializationFactory = deserializationFactory;\r
+    }\r
+}
\ No newline at end of file
diff --git a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFDatagramPacketEncoder.java b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFDatagramPacketEncoder.java
new file mode 100644 (file)
index 0000000..631509d
--- /dev/null
@@ -0,0 +1,56 @@
+/*\r
+ * Copyright (c) 2014 Pantheon Technologies s.r.o. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.openflowjava.protocol.impl.core;\r
+\r
+import java.util.List;\r
+\r
+import org.opendaylight.openflowjava.protocol.impl.connection.UdpMessageListenerWrapper;\r
+import org.opendaylight.openflowjava.protocol.impl.serialization.SerializationFactory;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+\r
+import io.netty.buffer.ByteBuf;\r
+import io.netty.buffer.PooledByteBufAllocator;\r
+import io.netty.channel.ChannelHandlerContext;\r
+import io.netty.channel.socket.DatagramPacket;\r
+import io.netty.handler.codec.MessageToMessageEncoder;\r
+import io.netty.util.concurrent.Future;\r
+\r
+/**\r
+ * @author michal.polkorab\r
+ *\r
+ */\r
+public class OFDatagramPacketEncoder extends MessageToMessageEncoder<UdpMessageListenerWrapper> {\r
+\r
+    private static final Logger LOGGER = LoggerFactory.getLogger(OFDatagramPacketEncoder.class);\r
+    private SerializationFactory serializationFactory;\r
+\r
+    @Override\r
+    protected void encode(ChannelHandlerContext ctx,\r
+            UdpMessageListenerWrapper wrapper, List<Object> out) throws Exception {\r
+        LOGGER.trace("Encoding");\r
+        try {\r
+            ByteBuf buffer = PooledByteBufAllocator.DEFAULT.buffer();\r
+            serializationFactory.messageToBuffer(wrapper.getMsg().getVersion(), buffer, wrapper.getMsg());\r
+            out.add(new DatagramPacket(buffer, wrapper.getAddress()));\r
+        } catch(Exception e) {\r
+            LOGGER.warn("Message serialization failed: {}", e.getMessage());\r
+            Future<Void> newFailedFuture = ctx.newFailedFuture(e);\r
+            wrapper.getListener().operationComplete(newFailedFuture);\r
+            return;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * @param serializationFactory\r
+     */\r
+    public void setSerializationFactory(SerializationFactory serializationFactory) {\r
+        this.serializationFactory = serializationFactory;\r
+    }\r
+}
\ No newline at end of file
diff --git a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFDatagramPacketHandler.java b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFDatagramPacketHandler.java
new file mode 100644 (file)
index 0000000..0f1b823
--- /dev/null
@@ -0,0 +1,105 @@
+/*\r
+ * Copyright (c) 2014 Pantheon Technologies s.r.o. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.openflowjava.protocol.impl.core;\r
+\r
+import io.netty.buffer.ByteBuf;\r
+import io.netty.channel.ChannelHandlerContext;\r
+import io.netty.channel.socket.DatagramPacket;\r
+import io.netty.handler.codec.MessageToMessageDecoder;\r
+\r
+import java.util.List;\r
+\r
+import org.opendaylight.openflowjava.protocol.api.connection.SwitchConnectionHandler;\r
+import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;\r
+import org.opendaylight.openflowjava.protocol.impl.connection.ConnectionAdapterFactory;\r
+import org.opendaylight.openflowjava.protocol.impl.connection.ConnectionAdapterFactoryImpl;\r
+import org.opendaylight.openflowjava.protocol.impl.connection.ConnectionFacade;\r
+import org.opendaylight.openflowjava.protocol.impl.connection.MessageConsumer;\r
+import org.opendaylight.openflowjava.util.ByteBufUtils;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+\r
+/**\r
+ * @author michal.polkorab\r
+ *\r
+ */\r
+public class OFDatagramPacketHandler extends MessageToMessageDecoder<DatagramPacket> {\r
+\r
+    private static final Logger LOGGER = LoggerFactory.getLogger(OFDatagramPacketHandler.class);\r
+\r
+    /** Length of OpenFlow 1.3 header */\r
+    public static final byte LENGTH_OF_HEADER = 8;\r
+    private static final byte LENGTH_INDEX_IN_HEADER = 2;\r
+    private ConnectionAdapterFactory adapterFactory = new ConnectionAdapterFactoryImpl();\r
+    private SwitchConnectionHandler connectionHandler;\r
+\r
+    /**\r
+     * Default constructor\r
+     * @param sch the switchConnectionHandler that decides\r
+     * what to do with incomming message / channel\r
+     */\r
+    public OFDatagramPacketHandler(SwitchConnectionHandler sch) {\r
+        this.connectionHandler = sch;\r
+    }\r
+\r
+    @Override\r
+    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {\r
+        LOGGER.warn("Unexpected exception from downstream.", cause);\r
+        LOGGER.warn("Closing connection.");\r
+        ctx.close();\r
+    }\r
+\r
+    @Override\r
+    protected void decode(ChannelHandlerContext ctx, DatagramPacket msg,\r
+            List<Object> out) throws Exception {\r
+        LOGGER.debug("OFDatagramPacketFramer");\r
+        MessageConsumer consumer = UdpConnectionMap.getMessageConsumer(msg.sender());\r
+        if (consumer == null) {\r
+            ConnectionFacade connectionFacade =\r
+                    adapterFactory.createConnectionFacade(ctx.channel(), msg.sender());\r
+            connectionHandler.onSwitchConnected(connectionFacade);\r
+            connectionFacade.checkListeners();\r
+            UdpConnectionMap.addConnection(msg.sender(), connectionFacade);\r
+        }\r
+        ByteBuf bb = msg.content();\r
+        int readableBytes = bb.readableBytes();\r
+        if (readableBytes < LENGTH_OF_HEADER) {\r
+            if (LOGGER.isDebugEnabled()) {\r
+                LOGGER.debug("skipping bytebuf - too few bytes for header: " + readableBytes + " < " + LENGTH_OF_HEADER );\r
+                LOGGER.debug("bb: " + ByteBufUtils.byteBufToHexString(bb));\r
+            }\r
+            return;\r
+        }\r
+\r
+        int length = bb.getUnsignedShort(bb.readerIndex() + LENGTH_INDEX_IN_HEADER);\r
+        LOGGER.debug("length of actual message: {}", length);\r
+        \r
+        if (readableBytes < length) {\r
+            if (LOGGER.isDebugEnabled()) {\r
+                LOGGER.debug("skipping bytebuf - too few bytes for msg: " +\r
+                        readableBytes + " < " + length);\r
+                LOGGER.debug("bytebuffer: " + ByteBufUtils.byteBufToHexString(bb));\r
+            }\r
+            return;\r
+        }\r
+        LOGGER.debug("OF Protocol message received, type:{}", bb.getByte(bb.readerIndex() + 1));\r
+\r
+        \r
+        byte version = bb.readByte();\r
+        if ((version == EncodeConstants.OF13_VERSION_ID) || (version == EncodeConstants.OF10_VERSION_ID)) {\r
+            LOGGER.debug("detected version: " + version);\r
+            ByteBuf messageBuffer = bb.slice();\r
+            out.add(new VersionMessageUdpWrapper(version, messageBuffer, msg.sender()));\r
+            messageBuffer.retain();\r
+        } else {\r
+            LOGGER.warn("detected version: " + version + " - currently not supported");\r
+        }\r
+        bb.skipBytes(bb.readableBytes());\r
+    }\r
+}
\ No newline at end of file
diff --git a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/PipelineHandlers.java b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/PipelineHandlers.java
new file mode 100644 (file)
index 0000000..9a9bf3c
--- /dev/null
@@ -0,0 +1,63 @@
+/*\r
+ * Copyright (c) 2014 Pantheon Technologies s.r.o. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.openflowjava.protocol.impl.core;\r
+\r
+/**\r
+ * Stores names of handlers used in pipeline.\r
+ * \r
+ * @author michal.polkorab\r
+ */\r
+public enum PipelineHandlers {\r
+\r
+    /**\r
+     * Detects switch idle state\r
+     */\r
+    IDLE_HANDLER,\r
+    /**\r
+     * Component for handling TLS frames\r
+     */\r
+    SSL_HANDLER,\r
+    /**\r
+     * Decodes incoming messages into message frames\r
+     */\r
+    OF_FRAME_DECODER,\r
+    /**\r
+     * Detects version of incoming OpenFlow Protocol message\r
+     */\r
+    OF_VERSION_DETECTOR,\r
+    /**\r
+     * Transforms OpenFlow Protocol byte messages into POJOs\r
+     */\r
+    OF_DECODER,\r
+    /**\r
+     * Transforms POJOs into OpenFlow Protocol byte messages\r
+     */\r
+    OF_ENCODER,\r
+    /**\r
+     * Delegates translated POJOs into MessageConsumer\r
+     */\r
+    DELEGATING_INBOUND_HANDLER,\r
+    /**\r
+     * Performs efficient flushing\r
+     */\r
+    CHANNEL_OUTBOUNF_QUEUE,\r
+    /**\r
+     * Decodes incoming messages into message frames\r
+     * and filters them based on version supported\r
+     */\r
+    OF_DATAGRAMPACKET_HANDLER,\r
+    /**\r
+     * Transforms OpenFlow Protocol datagram messages into POJOs\r
+     */\r
+    OF_DATAGRAMPACKET_DECODER,\r
+    /**\r
+     * Transforms POJOs into OpenFlow Protocol datagrams\r
+     */\r
+    OF_DATAGRAMPACKET_ENCODER\r
+}
\ No newline at end of file
diff --git a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/ProtocolChannelInitializer.java b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/ProtocolChannelInitializer.java
new file mode 100644 (file)
index 0000000..2c486f0
--- /dev/null
@@ -0,0 +1,101 @@
+/*\r
+ * Copyright (c) 2014 Pantheon Technologies s.r.o. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.openflowjava.protocol.impl.core;\r
+\r
+import io.netty.channel.Channel;\r
+import io.netty.channel.ChannelInitializer;\r
+\r
+import org.opendaylight.openflowjava.protocol.api.connection.SwitchConnectionHandler;\r
+import org.opendaylight.openflowjava.protocol.api.connection.TlsConfiguration;\r
+import org.opendaylight.openflowjava.protocol.impl.deserialization.DeserializationFactory;\r
+import org.opendaylight.openflowjava.protocol.impl.serialization.SerializationFactory;\r
+\r
+/**\r
+ * @param <CHANNEL_TYPE> Channel type\r
+ * @author michal.polkorab\r
+ */\r
+public abstract class ProtocolChannelInitializer<CHANNEL_TYPE extends Channel>\r
+        extends ChannelInitializer<CHANNEL_TYPE> {\r
+\r
+    private SwitchConnectionHandler switchConnectionHandler;\r
+    private long switchIdleTimeout;\r
+    private SerializationFactory serializationFactory;\r
+    private DeserializationFactory deserializationFactory;\r
+    private TlsConfiguration tlsConfiguration;\r
+\r
+    /**\r
+     * @param switchConnectionHandler the switchConnectionHandler to set\r
+     */\r
+    public void setSwitchConnectionHandler(final SwitchConnectionHandler switchConnectionHandler) {\r
+        this.switchConnectionHandler = switchConnectionHandler;\r
+    }\r
+\r
+    /**\r
+     * @param switchIdleTimeout the switchIdleTimeout to set\r
+     */\r
+    public void setSwitchIdleTimeout(final long switchIdleTimeout) {\r
+        this.switchIdleTimeout = switchIdleTimeout;\r
+    }\r
+\r
+    /**\r
+     * @param serializationFactory\r
+     */\r
+    public void setSerializationFactory(final SerializationFactory serializationFactory) {\r
+        this.serializationFactory = serializationFactory;\r
+    }\r
+\r
+    /**\r
+     * @param deserializationFactory\r
+     */\r
+    public void setDeserializationFactory(final DeserializationFactory deserializationFactory) {\r
+        this.deserializationFactory = deserializationFactory;\r
+    }\r
+\r
+    /**\r
+     * @param tlsConfiguration\r
+     */\r
+    public void setTlsConfiguration(TlsConfiguration tlsConfiguration) {\r
+        this.tlsConfiguration = tlsConfiguration;\r
+    }\r
+\r
+    /**\r
+     * @return switch connection handler\r
+     */\r
+    public SwitchConnectionHandler getSwitchConnectionHandler() {\r
+        return switchConnectionHandler;\r
+    }\r
+\r
+    /**\r
+     * @return switch idle timeout\r
+     */\r
+    public long getSwitchIdleTimeout() {\r
+        return switchIdleTimeout;\r
+    }\r
+\r
+    /**\r
+     * @return serialization factory\r
+     */\r
+    public SerializationFactory getSerializationFactory() {\r
+        return serializationFactory;\r
+    }\r
+\r
+    /**\r
+     * @return deserialization factory\r
+     */\r
+    public DeserializationFactory getDeserializationFactory() {\r
+        return deserializationFactory;\r
+    }\r
+\r
+    /**\r
+     * @return TLS configuration\r
+     */\r
+    public TlsConfiguration getTlsConfiguration() {\r
+        return tlsConfiguration;\r
+    }\r
+}
\ No newline at end of file
diff --git a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/PublishingChannelInitializer.java b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/PublishingChannelInitializer.java
deleted file mode 100644 (file)
index 5d29e4b..0000000
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright (c) 2013 Pantheon Technologies s.r.o. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.openflowjava.protocol.impl.core;
-
-import io.netty.channel.Channel;
-import io.netty.channel.ChannelInitializer;
-import io.netty.channel.group.DefaultChannelGroup;
-import io.netty.channel.socket.SocketChannel;
-import io.netty.handler.ssl.SslHandler;
-
-import java.net.InetAddress;
-import java.util.Iterator;
-import java.util.concurrent.TimeUnit;
-
-import javax.net.ssl.SSLEngine;
-
-import org.opendaylight.openflowjava.protocol.api.connection.SwitchConnectionHandler;
-import org.opendaylight.openflowjava.protocol.api.connection.TlsConfiguration;
-import org.opendaylight.openflowjava.protocol.impl.connection.ConnectionAdapterFactory;
-import org.opendaylight.openflowjava.protocol.impl.connection.ConnectionAdapterFactoryImpl;
-import org.opendaylight.openflowjava.protocol.impl.connection.ConnectionFacade;
-import org.opendaylight.openflowjava.protocol.impl.deserialization.DeserializationFactory;
-import org.opendaylight.openflowjava.protocol.impl.serialization.SerializationFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Initializes the channel
- * @author michal.polkorab
- */
-public class PublishingChannelInitializer extends ChannelInitializer<SocketChannel> {
-
-    /**
-     * Enum used for storing names of used components (in pipeline).
-     */
-    public static enum COMPONENT_NAMES {
-
-        /**
-         * Detects switch idle state
-         */
-        IDLE_HANDLER,
-        /**
-         * Detects TLS connections
-         */
-        TLS_DETECTOR,
-        /**
-         * Component for handling TLS frames
-         */
-        SSL_HANDLER,
-        /**
-         * Decodes incoming messages into message frames
-         */
-        OF_FRAME_DECODER,
-        /**
-         * Detects version of incoming OpenFlow Protocol message
-         */
-        OF_VERSION_DETECTOR,
-        /**
-         * Transforms OpenFlow Protocol byte messages into POJOs
-         */
-        OF_DECODER,
-        /**
-         * Transforms POJOs into OpenFlow Protocol byte messages
-         */
-        OF_ENCODER,
-        /**
-         * Delegates translated POJOs into MessageConsumer
-         */
-        DELEGATING_INBOUND_HANDLER,
-    }
-
-    private static final Logger LOGGER = LoggerFactory
-            .getLogger(PublishingChannelInitializer.class);
-    private final DefaultChannelGroup allChannels;
-    private SwitchConnectionHandler switchConnectionHandler;
-    private long switchIdleTimeout;
-    private SerializationFactory serializationFactory;
-    private DeserializationFactory deserializationFactory;
-    private ConnectionAdapterFactory connectionAdapterFactory;
-    private TlsConfiguration tlsConfiguration ;
-
-    /**
-     * default ctor
-     */
-    public PublishingChannelInitializer() {
-        this( new DefaultChannelGroup("netty-receiver", null), new ConnectionAdapterFactoryImpl() );
-    }
-
-    /**
-     * Testing Constructor
-     * 
-     */
-    protected PublishingChannelInitializer( DefaultChannelGroup channelGroup, ConnectionAdapterFactory connAdaptorFactory ) {
-       allChannels = channelGroup ;
-       connectionAdapterFactory = connAdaptorFactory ;
-    }
-    
-    @Override
-    protected void initChannel(final SocketChannel ch) {
-        InetAddress switchAddress = ch.remoteAddress().getAddress();
-        int port = ch.localAddress().getPort();
-        int remotePort = ch.remoteAddress().getPort();
-        LOGGER.info("Incoming connection from (remote address): " + switchAddress.toString()
-                + ":" + remotePort + " --> :" + port);
-        if (!switchConnectionHandler.accept(switchAddress)) {
-            ch.disconnect();
-            LOGGER.info("Incoming connection rejected");
-            return;
-        }
-        LOGGER.info("Incoming connection accepted - building pipeline");
-        allChannels.add(ch);
-        ConnectionFacade connectionFacade = null;
-        connectionFacade = connectionAdapterFactory.createConnectionFacade(ch);
-        try {
-            LOGGER.debug("calling plugin: " + switchConnectionHandler);
-            switchConnectionHandler.onSwitchConnected(connectionFacade);
-            connectionFacade.checkListeners();
-            ch.pipeline().addLast(COMPONENT_NAMES.IDLE_HANDLER.name(), new IdleHandler(switchIdleTimeout, TimeUnit.MILLISECONDS));
-            
-            // If this channel is configured to support SSL it will only support SSL
-            if (tlsConfiguration != null) {
-                SslContextFactory sslFactory = new SslContextFactory(tlsConfiguration);
-                SSLEngine engine = sslFactory.getServerContext().createSSLEngine();
-                engine.setNeedClientAuth(true);
-                engine.setUseClientMode(false);
-                ch.pipeline().addLast(COMPONENT_NAMES.SSL_HANDLER.name(), new SslHandler(engine));
-            }
-            ch.pipeline().addLast(COMPONENT_NAMES.OF_FRAME_DECODER.name(), new OFFrameDecoder(connectionFacade));
-            ch.pipeline().addLast(COMPONENT_NAMES.OF_VERSION_DETECTOR.name(), new OFVersionDetector());
-            OFDecoder ofDecoder = new OFDecoder();
-            ofDecoder.setDeserializationFactory(deserializationFactory);
-            ch.pipeline().addLast(COMPONENT_NAMES.OF_DECODER.name(), ofDecoder);
-            OFEncoder ofEncoder = new OFEncoder();
-            ofEncoder.setSerializationFactory(serializationFactory);
-            ch.pipeline().addLast(COMPONENT_NAMES.OF_ENCODER.name(), ofEncoder);
-            ch.pipeline().addLast(COMPONENT_NAMES.DELEGATING_INBOUND_HANDLER.name(), new DelegatingInboundHandler(connectionFacade));
-            if (tlsConfiguration == null) {
-                connectionFacade.fireConnectionReadyNotification();
-            }
-        } catch (Exception e) {
-            LOGGER.error("Failed to initialize channel", e);
-            ch.close();
-        }
-    }
-
-    /**
-     * @return iterator through active connections
-     */
-    public Iterator<Channel> getConnectionIterator() {
-        return allChannels.iterator();
-    }
-
-    /**
-     * @return amount of active channels
-     */
-    public int size() {
-        return allChannels.size();
-    }
-
-    /**
-     * @param switchConnectionHandler the switchConnectionHandler to set
-     */
-    public void setSwitchConnectionHandler(final SwitchConnectionHandler switchConnectionHandler) {
-        this.switchConnectionHandler = switchConnectionHandler;
-    }
-
-    /**
-     * @param switchIdleTimeout the switchIdleTimeout to set
-     */
-    public void setSwitchIdleTimeout(final long switchIdleTimeout) {
-        this.switchIdleTimeout = switchIdleTimeout;
-    }
-
-    /**
-     * @param serializationFactory
-     */
-    public void setSerializationFactory(final SerializationFactory serializationFactory) {
-        this.serializationFactory = serializationFactory;
-    }
-
-    /**
-     * @param deserializationFactory
-     */
-    public void setDeserializationFactory(final DeserializationFactory deserializationFactory) {
-        this.deserializationFactory = deserializationFactory;
-    }
-
-    /**
-     * @param tlsConfiguration
-     */
-    public void setTlsConfiguration(TlsConfiguration tlsConfiguration) {
-        this.tlsConfiguration = tlsConfiguration;
-    }
-}
diff --git a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/TcpChannelInitializer.java b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/TcpChannelInitializer.java
new file mode 100644 (file)
index 0000000..d84126b
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2013 Pantheon Technologies s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowjava.protocol.impl.core;
+
+import io.netty.channel.Channel;
+import io.netty.channel.group.DefaultChannelGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.handler.ssl.SslHandler;
+
+import java.net.InetAddress;
+import java.util.Iterator;
+import java.util.concurrent.TimeUnit;
+
+import javax.net.ssl.SSLEngine;
+
+import org.opendaylight.openflowjava.protocol.impl.connection.ConnectionAdapterFactory;
+import org.opendaylight.openflowjava.protocol.impl.connection.ConnectionAdapterFactoryImpl;
+import org.opendaylight.openflowjava.protocol.impl.connection.ConnectionFacade;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Initializes TCP / TLS channel
+ * @author michal.polkorab
+ */
+public class TcpChannelInitializer extends ProtocolChannelInitializer<SocketChannel> {
+
+    private static final Logger LOGGER = LoggerFactory
+            .getLogger(TcpChannelInitializer.class);
+    private final DefaultChannelGroup allChannels;
+    private ConnectionAdapterFactory connectionAdapterFactory;
+
+    /**
+     * default ctor
+     */
+    public TcpChannelInitializer() {
+        this( new DefaultChannelGroup("netty-receiver", null), new ConnectionAdapterFactoryImpl() );
+    }
+
+    /**
+     * Testing Constructor
+     * 
+     */
+    protected TcpChannelInitializer( DefaultChannelGroup channelGroup, ConnectionAdapterFactory connAdaptorFactory ) {
+       allChannels = channelGroup ;
+       connectionAdapterFactory = connAdaptorFactory ;
+    }
+    
+    @Override
+    protected void initChannel(final SocketChannel ch) {
+        InetAddress switchAddress = ch.remoteAddress().getAddress();
+        int port = ch.localAddress().getPort();
+        int remotePort = ch.remoteAddress().getPort();
+        LOGGER.info("Incoming connection from (remote address): " + switchAddress.toString()
+                + ":" + remotePort + " --> :" + port);
+        if (!getSwitchConnectionHandler().accept(switchAddress)) {
+            ch.disconnect();
+            LOGGER.info("Incoming connection rejected");
+            return;
+        }
+        LOGGER.info("Incoming connection accepted - building pipeline");
+        allChannels.add(ch);
+        ConnectionFacade connectionFacade = null;
+        connectionFacade = connectionAdapterFactory.createConnectionFacade(ch, null);
+        try {
+            LOGGER.debug("calling plugin: " + getSwitchConnectionHandler());
+            getSwitchConnectionHandler().onSwitchConnected(connectionFacade);
+            connectionFacade.checkListeners();
+            ch.pipeline().addLast(PipelineHandlers.IDLE_HANDLER.name(), new IdleHandler(getSwitchIdleTimeout(), TimeUnit.MILLISECONDS));
+            
+            // If this channel is configured to support SSL it will only support SSL
+            if (getTlsConfiguration() != null) {
+                SslContextFactory sslFactory = new SslContextFactory(getTlsConfiguration());
+                SSLEngine engine = sslFactory.getServerContext().createSSLEngine();
+                engine.setNeedClientAuth(true);
+                engine.setUseClientMode(false);
+                ch.pipeline().addLast(PipelineHandlers.SSL_HANDLER.name(), new SslHandler(engine));
+            }
+            ch.pipeline().addLast(PipelineHandlers.OF_FRAME_DECODER.name(), new OFFrameDecoder(connectionFacade));
+            ch.pipeline().addLast(PipelineHandlers.OF_VERSION_DETECTOR.name(), new OFVersionDetector());
+            OFDecoder ofDecoder = new OFDecoder();
+            ofDecoder.setDeserializationFactory(getDeserializationFactory());
+            ch.pipeline().addLast(PipelineHandlers.OF_DECODER.name(), ofDecoder);
+            OFEncoder ofEncoder = new OFEncoder();
+            ofEncoder.setSerializationFactory(getSerializationFactory());
+            ch.pipeline().addLast(PipelineHandlers.OF_ENCODER.name(), ofEncoder);
+            ch.pipeline().addLast(PipelineHandlers.DELEGATING_INBOUND_HANDLER.name(), new DelegatingInboundHandler(connectionFacade));
+            if (getTlsConfiguration() == null) {
+                connectionFacade.fireConnectionReadyNotification();
+            }
+        } catch (Exception e) {
+            LOGGER.error("Failed to initialize channel", e);
+            ch.close();
+        }
+    }
+
+    /**
+     * @return iterator through active connections
+     */
+    public Iterator<Channel> getConnectionIterator() {
+        return allChannels.iterator();
+    }
+
+    /**
+     * @return amount of active channels
+     */
+    public int size() {
+        return allChannels.size();
+    }
+}
\ No newline at end of file
index 72c5d07df0149704840c168e90d299128552185b..59675b2700172c8df5bb34c7ae47ae0c198a9cce 100644 (file)
@@ -30,7 +30,7 @@ import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.SettableFuture;
 
 /**
- * Class implementing server over TCP for handling incoming connections.
+ * Class implementing server over TCP / TLS for handling incoming connections.
  *
  * @author michal.polkorab
  */
@@ -56,7 +56,7 @@ public class TcpHandler implements ServerFacade {
     private final SettableFuture<Boolean> isOnlineFuture;
     private ThreadConfiguration threadConfig;
 
-    private PublishingChannelInitializer channelInitializer;
+    private TcpChannelInitializer channelInitializer;
 
     /**
      * Constructor of TCPHandler that listens on selected port.
@@ -135,7 +135,7 @@ public class TcpHandler implements ServerFacade {
 
             LOGGER.debug("address from tcphandler: {}", address);
             isOnlineFuture.set(true);
-            LOGGER.info("Switch listener started and ready to accept incoming connections on port: {}", port);
+            LOGGER.info("Switch listener started and ready to accept incoming tcp/tls connections on port: {}", port);
             f.channel().closeFuture().sync();
         } catch (InterruptedException e) {
             LOGGER.error("Interrupted while waiting for port {} shutdown", port, e);
@@ -197,13 +197,11 @@ public class TcpHandler implements ServerFacade {
     /**
      * @param channelInitializer
      */
-    public void setChannelInitializer(PublishingChannelInitializer channelInitializer) {
+    public void setChannelInitializer(TcpChannelInitializer channelInitializer) {
         this.channelInitializer = channelInitializer;
     }
 
-    /**
-     * @param threadConfig EventLoopGroup configuration
-     */
+    @Override
     public void setThreadConfig(ThreadConfiguration threadConfig) {
         this.threadConfig = threadConfig;
     }
diff --git a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/UdpChannelInitializer.java b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/UdpChannelInitializer.java
new file mode 100644 (file)
index 0000000..5187144
--- /dev/null
@@ -0,0 +1,32 @@
+/*\r
+ * Copyright (c) 2014 Pantheon Technologies s.r.o. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.openflowjava.protocol.impl.core;\r
+\r
+import io.netty.channel.socket.nio.NioDatagramChannel;\r
+\r
+/**\r
+ * @author michal.polkorab\r
+ *\r
+ */\r
+public class UdpChannelInitializer extends ProtocolChannelInitializer<NioDatagramChannel> {\r
+\r
+    @Override\r
+    protected void initChannel(NioDatagramChannel ch) throws Exception {\r
+        ch.pipeline().addLast(PipelineHandlers.OF_DATAGRAMPACKET_HANDLER.name(),\r
+                new OFDatagramPacketHandler(getSwitchConnectionHandler()));\r
+        OFDatagramPacketDecoder ofDatagramPacketDecoder = new OFDatagramPacketDecoder();\r
+        ofDatagramPacketDecoder.setDeserializationFactory(getDeserializationFactory());\r
+        ch.pipeline().addLast(PipelineHandlers.OF_DATAGRAMPACKET_DECODER.name(),\r
+                ofDatagramPacketDecoder);\r
+        OFDatagramPacketEncoder ofDatagramPacketEncoder = new OFDatagramPacketEncoder();\r
+        ofDatagramPacketEncoder.setSerializationFactory(getSerializationFactory());\r
+        ch.pipeline().addLast(PipelineHandlers.OF_ENCODER.name(), ofDatagramPacketEncoder);\r
+//        connectionFacade.fireConnectionReadyNotification();\r
+    }\r
+}
\ No newline at end of file
diff --git a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/UdpConnectionMap.java b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/UdpConnectionMap.java
new file mode 100644 (file)
index 0000000..ce6d17f
--- /dev/null
@@ -0,0 +1,48 @@
+/*\r
+ * Copyright (c) 2014 Pantheon Technologies s.r.o. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.openflowjava.protocol.impl.core;\r
+\r
+import java.net.InetSocketAddress;\r
+import java.util.HashMap;\r
+\r
+import org.opendaylight.openflowjava.protocol.impl.connection.MessageConsumer;\r
+\r
+/**\r
+ * As UDP communication is handled only by one channel, it is needed\r
+ * to store MessageConsumers, so that we know which consumer handles which channel\r
+\r
+ * @author michal.polkorab\r
+ */\r
+public class UdpConnectionMap {\r
+\r
+    private static HashMap<InetSocketAddress, MessageConsumer> connectionMap = new HashMap<>();\r
+\r
+    /**\r
+     * @param address sender's address\r
+     * @return corresponding MessageConsumer\r
+     */\r
+    public static MessageConsumer getMessageConsumer(InetSocketAddress address) {\r
+        return connectionMap.get(address);\r
+    }\r
+\r
+    /**\r
+     * @param address sender's address\r
+     * @param consumer MessageConsumer to be added / paired with specified address\r
+     */\r
+    public static void addConnection(InetSocketAddress address, MessageConsumer consumer) {\r
+        connectionMap.put(address, consumer);\r
+    }\r
+\r
+    /**\r
+     * @param address sender's address\r
+     */\r
+    public static void removeConnection(InetSocketAddress address) {\r
+        connectionMap.remove(address);\r
+    }\r
+}
\ No newline at end of file
diff --git a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/UdpHandler.java b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/UdpHandler.java
new file mode 100644 (file)
index 0000000..c0f958d
--- /dev/null
@@ -0,0 +1,151 @@
+/*\r
+ * Copyright (c) 2014 Pantheon Technologies s.r.o. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.openflowjava.protocol.impl.core;\r
+\r
+import io.netty.bootstrap.Bootstrap;\r
+import io.netty.channel.ChannelFuture;\r
+import io.netty.channel.ChannelOption;\r
+import io.netty.channel.EventLoopGroup;\r
+import io.netty.channel.nio.NioEventLoopGroup;\r
+import io.netty.channel.socket.nio.NioDatagramChannel;\r
+import io.netty.util.concurrent.GenericFutureListener;\r
+\r
+import java.net.InetAddress;\r
+import java.net.InetSocketAddress;\r
+\r
+import org.opendaylight.openflowjava.protocol.api.connection.ThreadConfiguration;\r
+import org.opendaylight.openflowjava.protocol.impl.connection.ServerFacade;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+\r
+import com.google.common.util.concurrent.ListenableFuture;\r
+import com.google.common.util.concurrent.SettableFuture;\r
+\r
+/**\r
+ * Class implementing server over UDP for handling incoming connections.\r
+ * \r
+ * @author michal.polkorab\r
+ */\r
+public final class UdpHandler implements ServerFacade {\r
+\r
+    private static final Logger LOGGER = LoggerFactory\r
+            .getLogger(UdpHandler.class);\r
+    private int port;\r
+    private String address;\r
+    private EventLoopGroup group;\r
+    private final InetAddress startupAddress;\r
+    private final SettableFuture<Boolean> isOnlineFuture;\r
+    private UdpChannelInitializer channelInitializer;\r
+    private ThreadConfiguration threadConfig;\r
+\r
+    /**\r
+     * Constructor of UdpHandler that listens on selected port.\r
+     *\r
+     * @param port listening port of UdpHandler server\r
+     */\r
+    public UdpHandler(final int port) {\r
+        this(null, port);\r
+    }\r
+\r
+    /**\r
+     * Constructor of UdpHandler that listens on selected address and port.\r
+     * @param address listening address of UdpHandler server\r
+     * @param port listening port of UdpHandler server\r
+     */\r
+    public UdpHandler(final InetAddress address, final int port) {\r
+        this.port = port;\r
+        this.startupAddress = address;\r
+        isOnlineFuture = SettableFuture.create();\r
+    }\r
+\r
+    @Override\r
+    public void run() {\r
+        if (threadConfig != null) {\r
+            group = new NioEventLoopGroup(threadConfig.getWorkerThreadCount());\r
+        } else {\r
+            group = new NioEventLoopGroup();\r
+        }\r
+        final ChannelFuture f;\r
+        try {\r
+            Bootstrap b = new Bootstrap();\r
+            b.group(group)\r
+             .channel(NioDatagramChannel.class)\r
+             .option(ChannelOption.SO_BROADCAST, false)\r
+             .handler(channelInitializer);\r
+\r
+            if (startupAddress != null) {\r
+                f = b.bind(startupAddress.getHostAddress(), port).sync();\r
+            } else {\r
+                f = b.bind(port).sync();\r
+            }\r
+        } catch (InterruptedException e) {\r
+            LOGGER.error("Interrupted while binding port {}", port, e);\r
+            return;\r
+        }\r
+\r
+        try {\r
+            InetSocketAddress isa = (InetSocketAddress) f.channel().localAddress();\r
+            this.address = isa.getHostString();\r
+\r
+            // Update port, as it may have been specified as 0\r
+            this.port = isa.getPort();\r
+\r
+            LOGGER.debug("Address from udpHandler: {}", address);\r
+            isOnlineFuture.set(true);\r
+            LOGGER.info("Switch listener started and ready to accept incoming udp connections on port: {}", port);\r
+            f.channel().closeFuture().sync();\r
+        } catch (InterruptedException e) {\r
+            LOGGER.error("Interrupted while waiting for port {} shutdown", port, e);\r
+        } finally {\r
+            shutdown();\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public ListenableFuture<Boolean> shutdown() {\r
+        final SettableFuture<Boolean> result = SettableFuture.create();\r
+        group.shutdownGracefully().addListener(new GenericFutureListener<io.netty.util.concurrent.Future<Object>>() {\r
+\r
+            @Override\r
+            public void operationComplete(\r
+                    final io.netty.util.concurrent.Future<Object> downResult) throws Exception {\r
+                result.set(downResult.isSuccess());\r
+                if (downResult.cause() != null) {\r
+                    result.setException(downResult.cause());\r
+                }\r
+            }\r
+\r
+        });\r
+        return result;\r
+    }\r
+\r
+    @Override\r
+    public ListenableFuture<Boolean> getIsOnlineFuture() {\r
+        return isOnlineFuture;\r
+    }\r
+\r
+    /**\r
+     * @return the port\r
+     */\r
+    public int getPort() {\r
+        return port;\r
+    }\r
+\r
+    /**\r
+     * @param channelInitializer\r
+     */\r
+    public void setChannelInitializer(UdpChannelInitializer channelInitializer) {\r
+        this.channelInitializer = channelInitializer;\r
+    }\r
+\r
+    @Override\r
+    public void setThreadConfig(ThreadConfiguration threadConfig) {\r
+        this.threadConfig = threadConfig;\r
+    }\r
+}
\ No newline at end of file
diff --git a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/VersionMessageUdpWrapper.java b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/VersionMessageUdpWrapper.java
new file mode 100644 (file)
index 0000000..087bcb6
--- /dev/null
@@ -0,0 +1,40 @@
+/*\r
+ * Copyright (c) 2014 Pantheon Technologies s.r.o. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.openflowjava.protocol.impl.core;\r
+\r
+import io.netty.buffer.ByteBuf;\r
+\r
+import java.net.InetSocketAddress;\r
+\r
+/**\r
+ * Wraps received messages (includes version) and sender address\r
\r
+ * @author michal.polkorab\r
+ */\r
+public class VersionMessageUdpWrapper extends VersionMessageWrapper {\r
+\r
+    private InetSocketAddress address;\r
+\r
+    /**\r
+     * @param version Openflow wire version\r
+     * @param messageBuffer ByteBuf containing binary message\r
+     * @param address sender address\r
+     */\r
+    public VersionMessageUdpWrapper(short version, ByteBuf messageBuffer, InetSocketAddress address) {\r
+        super(version, messageBuffer);\r
+        this.address = address;\r
+    }\r
+\r
+    /**\r
+     * @return sender address\r
+     */\r
+    public InetSocketAddress getAddress() {\r
+        return address;\r
+    }\r
+}
\ No newline at end of file
index 1a22723a037b70f2941df5bef9979761228a4e18..b3cbeb29a936a701535ceb60f5bac6c15904a209 100644 (file)
@@ -18,6 +18,7 @@ import org.opendaylight.openflowjava.protocol.api.connection.TlsConfiguration;
 import org.opendaylight.openflowjava.protocol.impl.connection.SwitchConnectionProviderImpl;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.KeystoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.TransportProtocol;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -79,6 +80,7 @@ public final class SwitchConnectionProviderModule extends org.opendaylight.yang.
         final long switchIdleTimeout = getSwitchIdleTimeout();
         final Tls tlsConfig = getTls();
         final Threads threads = getThreads();
+        final TransportProtocol transportProtocol = getTransportProtocol();
         
         return new ConnectionConfiguration() {
             @Override
@@ -91,12 +93,11 @@ public final class SwitchConnectionProviderModule extends org.opendaylight.yang.
             }
             @Override
             public Object getTransferProtocol() {
-                // TODO Auto-generated method stub
-                return null;
+                return transportProtocol;
             }
             @Override
             public TlsConfiguration getTlsConfiguration() {
-                if (tlsConfig == null) {
+                if (tlsConfig == null || !(TransportProtocol.TLS.equals(transportProtocol))) {
                     return null;
                 }
                 return new TlsConfiguration() {
index dbc48866b02d1aed551d2382111d84122ed56939..6afd5c60a1b8aeea650e75b83c6fcee391f6267e 100644 (file)
@@ -36,6 +36,11 @@ module openflow-switch-connection-provider-impl {
                 description "address of local listening interface";
                 type ietf-inet:ip-address;
             }
+            leaf transport-protocol {
+                description "Transport protocol used for communication.";
+                type of-config:transport-protocol;
+                mandatory true;
+            }
             leaf switch-idle-timeout {
                 description "idle timeout in [ms]";
                 type uint32;
index b24192a1283556f8f849266bb04c74d635aad8c7..6001e7f84c52e36e03f28e6addef98b056ced20b 100644 (file)
@@ -29,7 +29,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.P
 public class PublishingChannelInitializerFactoryTest {
 
     TlsConfiguration tlsConfiguration ;
-    PublishingChannelInitializerFactory factory;
+    ChannelInitializerFactory factory;
     private final long switchIdleTimeOut = 60;
     @Mock SwitchConnectionHandler switchConnectionHandler ;
     @Mock SerializationFactory serializationFactory;
@@ -41,7 +41,7 @@ public class PublishingChannelInitializerFactoryTest {
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        factory = new PublishingChannelInitializerFactory();
+        factory = new ChannelInitializerFactory();
         tlsConfiguration = new TlsConfigurationImpl(KeystoreType.JKS, "/exemplary-ctlTrustStore",
                 PathType.CLASSPATH, KeystoreType.JKS, "/exemplary-ctlKeystore", PathType.CLASSPATH);
         factory.setDeserializationFactory(deserializationFactory);
@@ -52,11 +52,11 @@ public class PublishingChannelInitializerFactoryTest {
     }
 
     /**
-     * Test {@link PublishingChannelInitializer} creation
+     * Test {@link TcpChannelInitializer} creation
      */
     @Test
     public void testCreatePublishingChannelInitializer() {
-        PublishingChannelInitializer initializer = factory.createPublishingChannelInitializer() ;
+        TcpChannelInitializer initializer = factory.createPublishingChannelInitializer() ;
         assertNotNull( initializer );
     }
 }
\ No newline at end of file
index 6666da3de000c1cc6bd759cd8eae4fd34032cfa0..2a503dd259f434e42157fc01e31e6f5af3647c5b 100644 (file)
@@ -36,7 +36,6 @@ import org.opendaylight.openflowjava.protocol.api.connection.TlsConfiguration;
 import org.opendaylight.openflowjava.protocol.api.connection.TlsConfigurationImpl;
 import org.opendaylight.openflowjava.protocol.impl.connection.ConnectionAdapterFactory;
 import org.opendaylight.openflowjava.protocol.impl.connection.ConnectionFacade;
-import org.opendaylight.openflowjava.protocol.impl.core.PublishingChannelInitializer.COMPONENT_NAMES;
 import org.opendaylight.openflowjava.protocol.impl.deserialization.DeserializationFactory;
 import org.opendaylight.openflowjava.protocol.impl.serialization.SerializationFactory;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.KeystoreType;
@@ -63,7 +62,7 @@ public class PublishingChannelInitializerTest {
 
     TlsConfiguration tlsConfiguration ;
     InetSocketAddress inetSockAddr;
-    PublishingChannelInitializer pubChInitializer  ;
+    TcpChannelInitializer pubChInitializer  ;
 
     /**
      * Sets up test environment
@@ -72,7 +71,7 @@ public class PublishingChannelInitializerTest {
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        pubChInitializer= new PublishingChannelInitializer(mockChGrp, mockConnAdaptorFactory) ;
+        pubChInitializer= new TcpChannelInitializer(mockChGrp, mockConnAdaptorFactory) ;
         pubChInitializer.setSerializationFactory(mockSerializationFactory);
         pubChInitializer.setDeserializationFactory(mockDeserializationFactory);
         pubChInitializer.setSwitchIdleTimeout(1) ;
@@ -83,7 +82,7 @@ public class PublishingChannelInitializerTest {
 
         inetSockAddr = new InetSocketAddress(InetAddress.getLocalHost(), 8675 ) ;
 
-        when(mockConnAdaptorFactory.createConnectionFacade(mockSocketCh))
+        when(mockConnAdaptorFactory.createConnectionFacade(mockSocketCh, null))
         .thenReturn(mockConnFacade);
         when(mockSocketCh.remoteAddress()).thenReturn(inetSockAddr) ;
         when(mockSocketCh.localAddress()).thenReturn(inetSockAddr) ;
@@ -105,7 +104,7 @@ public class PublishingChannelInitializerTest {
         pubChInitializer.initChannel(mockSocketCh) ;
 
         verifyCommonHandlers();
-        verify(mockChPipeline, times(1)).addLast(eq(COMPONENT_NAMES.SSL_HANDLER.name()),any(SslHandler.class)) ;
+        verify(mockChPipeline, times(1)).addLast(eq(PipelineHandlers.SSL_HANDLER.name()),any(SslHandler.class)) ;
     }
 
     /**
@@ -117,7 +116,7 @@ public class PublishingChannelInitializerTest {
         pubChInitializer.initChannel(mockSocketCh) ;
 
         verifyCommonHandlers();
-        verify(mockChPipeline, times(0)).addLast(eq(COMPONENT_NAMES.SSL_HANDLER.name()),any(SslHandler.class)) ;
+        verify(mockChPipeline, times(0)).addLast(eq(PipelineHandlers.SSL_HANDLER.name()),any(SslHandler.class)) ;
     }
 
     /**
@@ -160,12 +159,12 @@ public class PublishingChannelInitializerTest {
      * All paths should install these six handlers:
      */
     private void verifyCommonHandlers() {
-        verify(mockChPipeline, times(1)).addLast(eq(COMPONENT_NAMES.IDLE_HANDLER.name()),any(IdleHandler.class)) ;
-        verify(mockChPipeline, times(1)).addLast(eq(COMPONENT_NAMES.OF_DECODER.name()),any(OFDecoder.class)) ;
-        verify(mockChPipeline, times(1)).addLast(eq(COMPONENT_NAMES.OF_ENCODER.name()),any(OFEncoder.class)) ;
-        verify(mockChPipeline, times(1)).addLast(eq(COMPONENT_NAMES.OF_FRAME_DECODER.name()),any(OFFrameDecoder.class)) ;
-        verify(mockChPipeline, times(1)).addLast(eq(COMPONENT_NAMES.OF_VERSION_DETECTOR.name()),any(OFVersionDetector.class)) ;
-        verify(mockChPipeline, times(1)).addLast(eq(COMPONENT_NAMES.DELEGATING_INBOUND_HANDLER.name()),any(DelegatingInboundHandler.class));
+        verify(mockChPipeline, times(1)).addLast(eq(PipelineHandlers.IDLE_HANDLER.name()),any(IdleHandler.class)) ;
+        verify(mockChPipeline, times(1)).addLast(eq(PipelineHandlers.OF_DECODER.name()),any(OFDecoder.class)) ;
+        verify(mockChPipeline, times(1)).addLast(eq(PipelineHandlers.OF_ENCODER.name()),any(OFEncoder.class)) ;
+        verify(mockChPipeline, times(1)).addLast(eq(PipelineHandlers.OF_FRAME_DECODER.name()),any(OFFrameDecoder.class)) ;
+        verify(mockChPipeline, times(1)).addLast(eq(PipelineHandlers.OF_VERSION_DETECTOR.name()),any(OFVersionDetector.class)) ;
+        verify(mockChPipeline, times(1)).addLast(eq(PipelineHandlers.DELEGATING_INBOUND_HANDLER.name()),any(DelegatingInboundHandler.class));
         assertEquals(1, pubChInitializer.size()) ;
     }
 }
index 7092922fe2a5f79ee34e3bb7b8d8b0622349c898..129a86681d1e188e9ac98fc583dc585dee29f5c0 100644 (file)
@@ -36,7 +36,7 @@ public class TcpHandlerTest {
 
     private InetAddress serverAddress = InetAddress.getLoopbackAddress() ;
     @Mock ChannelHandlerContext mockChHndlrCtx ;
-    @Mock PublishingChannelInitializer mockChannelInitializer;
+    @Mock TcpChannelInitializer mockChannelInitializer;
     @Mock SwitchConnectionHandler mockSwitchConnHndler ;
     @Mock SerializationFactory mockSerializationFactory ;
     @Mock DeserializationFactory mockDeserializationFactory ;
index d0a76c8f95884d75f15ad81dbd4f67565f2748a7..47c1889bb51c0e233fbea9ff2591114b3fbdd87e 100644 (file)
@@ -13,6 +13,7 @@ import java.net.InetAddress;
 import org.opendaylight.openflowjava.protocol.api.connection.ConnectionConfiguration;
 import org.opendaylight.openflowjava.protocol.api.connection.ThreadConfiguration;
 import org.opendaylight.openflowjava.protocol.api.connection.TlsConfiguration;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.TransportProtocol;
 
 /**
  * @author michal.polkorab
@@ -26,6 +27,7 @@ public class ConnectionConfigurationImpl implements ConnectionConfiguration {
     private TlsConfiguration tlsConfig;
     private long switchIdleTimeout;
     private ThreadConfiguration threadConfig;
+    private TransportProtocol protocol;
 
     /**
      * Creates {@link ConnectionConfigurationImpl}
@@ -56,6 +58,14 @@ public class ConnectionConfigurationImpl implements ConnectionConfiguration {
         return transferProtocol;
     }
 
+    /**
+     * Used for testing - sets transport protocol
+     * @param protocol
+     */
+    public void setTransferProtocol(TransportProtocol protocol) {
+        this.transferProtocol = protocol;
+    }
+
     @Override
     public long getSwitchIdleTimeout() {
         return switchIdleTimeout;
index c12ec55b8938c8263cc4e35d68685a4702a7e266..8a94cd0556d8897467570b0c81136aa544cc9bc2 100644 (file)
@@ -20,17 +20,21 @@ import org.junit.Test;
 import org.opendaylight.openflowjava.protocol.api.connection.TlsConfiguration;
 import org.opendaylight.openflowjava.protocol.api.connection.TlsConfigurationImpl;
 import org.opendaylight.openflowjava.protocol.impl.clients.ClientEvent;
+import org.opendaylight.openflowjava.protocol.impl.clients.OFClient;
 import org.opendaylight.openflowjava.protocol.impl.clients.ScenarioFactory;
 import org.opendaylight.openflowjava.protocol.impl.clients.ScenarioHandler;
 import org.opendaylight.openflowjava.protocol.impl.clients.SendEvent;
 import org.opendaylight.openflowjava.protocol.impl.clients.SimpleClient;
 import org.opendaylight.openflowjava.protocol.impl.clients.SleepEvent;
+import org.opendaylight.openflowjava.protocol.impl.clients.UdpSimpleClient;
 import org.opendaylight.openflowjava.protocol.impl.clients.WaitForMessageEvent;
 import org.opendaylight.openflowjava.protocol.impl.connection.SwitchConnectionProviderImpl;
 import org.opendaylight.openflowjava.protocol.impl.core.TcpHandler;
+import org.opendaylight.openflowjava.protocol.impl.core.UdpHandler;
 import org.opendaylight.openflowjava.util.ByteBufUtils;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.KeystoreType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.PathType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.TransportProtocol;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -44,7 +48,7 @@ public class IntegrationTest {
             .getLogger(IntegrationTest.class);
     
     private static int port;
-    private TlsConfiguration tlsConfiguration ;
+    private TlsConfiguration tlsConfiguration;
     private static final int SWITCH_IDLE_TIMEOUT = 2000;
     private static final long CONNECTION_TIMEOUT = 2000;
     private InetAddress startupAddress;
@@ -53,31 +57,36 @@ public class IntegrationTest {
     private ConnectionConfigurationImpl connConfig;
 
     /**
-     * @param secured true if an encrypted connection should be used
+     * @param protocol communication protocol to be used during test
      * @throws Exception
      */
-    public void setUp(boolean secured) throws Exception {
+    public void setUp(TransportProtocol protocol) throws Exception {
         LOGGER.debug("\n starting test -------------------------------");
         
         String currentDir = System.getProperty("user.dir");
         LOGGER.debug("Current dir using System:" +currentDir);
         startupAddress = InetAddress.getLocalHost();
-        if (secured) {
+        tlsConfiguration = null;
+        if (protocol.equals(TransportProtocol.TLS)) {
             tlsConfiguration = new TlsConfigurationImpl(KeystoreType.JKS,
                     "/selfSignedSwitch", PathType.CLASSPATH, KeystoreType.JKS,
                     "/selfSignedController", PathType.CLASSPATH) ;
-            connConfig = new ConnectionConfigurationImpl(startupAddress, 0, tlsConfiguration, SWITCH_IDLE_TIMEOUT);
-        } else {
-            connConfig = new ConnectionConfigurationImpl(startupAddress, 0, null, SWITCH_IDLE_TIMEOUT);
         }
+        connConfig = new ConnectionConfigurationImpl(startupAddress, 0, tlsConfiguration, SWITCH_IDLE_TIMEOUT);
+        connConfig.setTransferProtocol(protocol);
         mockPlugin = new MockPlugin();
         
         switchConnectionProvider = new SwitchConnectionProviderImpl();
         switchConnectionProvider.setSwitchConnectionHandler(mockPlugin);
         switchConnectionProvider.setConfiguration(connConfig);
         switchConnectionProvider.startup().get(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS);
-        TcpHandler tcpHandler = (TcpHandler) switchConnectionProvider.getServerFacade();
-        port = tcpHandler.getPort();
+        if (protocol.equals(TransportProtocol.TCP) || protocol.equals(TransportProtocol.TLS)) {
+            TcpHandler tcpHandler = (TcpHandler) switchConnectionProvider.getServerFacade();
+            port = tcpHandler.getPort();
+        } else {
+            UdpHandler udpHandler = (UdpHandler) switchConnectionProvider.getServerFacade();
+            port = udpHandler.getPort();
+        }
     }
 
     /**
@@ -87,7 +96,6 @@ public class IntegrationTest {
     public void tearDown() throws Exception {
         switchConnectionProvider.close();
         LOGGER.debug("\n ending test -------------------------------");
-
     }
 
     /**
@@ -96,12 +104,12 @@ public class IntegrationTest {
      */
     @Test
     public void testHandshake() throws Exception {
-        setUp(false);
+        setUp(TransportProtocol.TCP);
         int amountOfCLients = 1;
         Stack<ClientEvent> scenario = ScenarioFactory.createHandshakeScenario();
         ScenarioHandler handler = new ScenarioHandler(scenario);
-        List<SimpleClient> clients = createAndStartClient(amountOfCLients, handler, false);
-        SimpleClient firstClient = clients.get(0);
+        List<OFClient> clients = createAndStartClient(amountOfCLients, handler, TransportProtocol.TCP);
+        OFClient firstClient = clients.get(0);
         firstClient.getScenarioDone().get();
         Thread.sleep(1000);
         
@@ -109,17 +117,17 @@ public class IntegrationTest {
     }
 
     /**
-     * Library integration and communication test with handshake
+     * Library integration and secured communication test with handshake
      * @throws Exception 
      */
     @Test
     public void testTlsHandshake() throws Exception {
-        setUp(true);
+        setUp(TransportProtocol.TLS);
         int amountOfCLients = 1;
         Stack<ClientEvent> scenario = ScenarioFactory.createHandshakeScenario();
         ScenarioHandler handler = new ScenarioHandler(scenario);
-        List<SimpleClient> clients = createAndStartClient(amountOfCLients, handler, true);
-        SimpleClient firstClient = clients.get(0);
+        List<OFClient> clients = createAndStartClient(amountOfCLients, handler, TransportProtocol.TLS);
+        OFClient firstClient = clients.get(0);
         firstClient.getScenarioDone().get();
         Thread.sleep(1000);
         
@@ -132,7 +140,7 @@ public class IntegrationTest {
      */
     @Test
     public void testHandshakeAndEcho() throws Exception {
-        setUp(false);
+        setUp(TransportProtocol.TCP);
         int amountOfCLients = 1;
         Stack<ClientEvent> scenario = ScenarioFactory.createHandshakeScenario();
         scenario.add(0, new SleepEvent(1000));
@@ -140,20 +148,20 @@ public class IntegrationTest {
         scenario.add(0, new SleepEvent(1000));
         scenario.add(0, new WaitForMessageEvent(ByteBufUtils.hexStringToBytes("04 03 00 08 00 00 00 04")));
         ScenarioHandler handler = new ScenarioHandler(scenario);
-        List<SimpleClient> clients = createAndStartClient(amountOfCLients, handler, false);
-        SimpleClient firstClient = clients.get(0);
+        List<OFClient> clients = createAndStartClient(amountOfCLients, handler, TransportProtocol.TCP);
+        OFClient firstClient = clients.get(0);
         firstClient.getScenarioDone().get();
 
         LOGGER.debug("testHandshakeAndEcho() Finished") ;
     }
 
     /**
-     * Library integration and communication test with handshake + echo exchange
+     * Library integration and secured communication test with handshake + echo exchange
      * @throws Exception 
      */
     @Test
     public void testTlsHandshakeAndEcho() throws Exception {
-        setUp(true);
+        setUp(TransportProtocol.TLS);
         int amountOfCLients = 1;
         Stack<ClientEvent> scenario = ScenarioFactory.createHandshakeScenario();
         scenario.add(0, new SleepEvent(1000));
@@ -161,40 +169,69 @@ public class IntegrationTest {
         scenario.add(0, new SleepEvent(1000));
         scenario.add(0, new WaitForMessageEvent(ByteBufUtils.hexStringToBytes("04 03 00 08 00 00 00 04")));
         ScenarioHandler handler = new ScenarioHandler(scenario);
-        List<SimpleClient> clients = createAndStartClient(amountOfCLients, handler, true);
-        SimpleClient firstClient = clients.get(0);
+        List<OFClient> clients = createAndStartClient(amountOfCLients, handler, TransportProtocol.TLS);
+        OFClient firstClient = clients.get(0);
         firstClient.getScenarioDone().get();
 
         LOGGER.debug("testTlsHandshakeAndEcho() Finished") ;
     }
 
     /**
-     * Library integration and communication test (with virtual machine)        
-     * @throws Exception        
-     */     
-    //@Test         
-    public void testCommunicationWithVM() throws Exception {        
-        mockPlugin.getFinishedFuture().get();       
+     * Library udp integration and communication test with handshake + echo exchange
+     * @throws Exception 
+     */
+    @Test
+    public void testUdpHandshakeAndEcho() throws Exception {
+        setUp(TransportProtocol.UDP);
+        int amountOfCLients = 1;
+        Stack<ClientEvent> scenario = ScenarioFactory.createHandshakeScenario();
+        scenario.add(0, new SleepEvent(1000));
+        scenario.add(0, new SendEvent(ByteBufUtils.hexStringToBytes("04 02 00 08 00 00 00 04")));
+        scenario.add(0, new SleepEvent(1000));
+        scenario.add(0, new WaitForMessageEvent(ByteBufUtils.hexStringToBytes("04 03 00 08 00 00 00 04")));
+        ScenarioHandler handler = new ScenarioHandler(scenario);
+        List<OFClient> clients = createAndStartClient(amountOfCLients, handler, TransportProtocol.UDP);
+        OFClient firstClient = clients.get(0);
+        firstClient.getScenarioDone().get();
+
+        LOGGER.debug("testUdpHandshakeAndEcho() Finished") ;
+    }
+
+    /**
+     * Library integration and communication test (with virtual machine)
+     * @throws Exception
+     */
+    //@Test
+    public void testCommunicationWithVM() throws Exception {
+        mockPlugin.getFinishedFuture().get();
     }
 
     /**
      * @param amountOfCLients 
-     * @param secured true if encrypted connection should be used
+     * @param protocol true if encrypted connection should be used
      * @return new clients up and running
      * @throws ExecutionException if some client could not start
      */
-    private List<SimpleClient> createAndStartClient(int amountOfCLients, ScenarioHandler scenarioHandler,
-            boolean secured) throws ExecutionException {
-        List<SimpleClient> clientsHorde = new ArrayList<>();
+    private List<OFClient> createAndStartClient(int amountOfCLients, ScenarioHandler scenarioHandler,
+            TransportProtocol protocol) throws ExecutionException {
+        List<OFClient> clientsHorde = new ArrayList<>();
         for (int i = 0; i < amountOfCLients; i++) {
             LOGGER.debug("startup address in createclient: " + startupAddress.getHostAddress());
-            SimpleClient sc = new SimpleClient(startupAddress.getHostAddress(), port);
-            sc.setSecuredClient(secured);
+            OFClient sc = null;
+            if (protocol.equals(TransportProtocol.TCP)) {
+                sc = new SimpleClient(startupAddress.getHostAddress(), port);
+                sc.setSecuredClient(false);
+            } else if (protocol.equals(TransportProtocol.TLS)) {
+                sc = new SimpleClient(startupAddress.getHostAddress(), port);
+                sc.setSecuredClient(true);
+            } else {
+                sc = new UdpSimpleClient(startupAddress.getHostAddress(), port);
+            }
             sc.setScenarioHandler(scenarioHandler);
             clientsHorde.add(sc);
-            sc.start();
+            sc.run();
         }
-        for (SimpleClient sc : clientsHorde) {
+        for (OFClient sc : clientsHorde) {
             try {
                 sc.getIsOnlineFuture().get(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS);
             } catch (Exception e) {
diff --git a/simple-client/src/main/java/org/opendaylight/openflowjava/protocol/impl/clients/OFClient.java b/simple-client/src/main/java/org/opendaylight/openflowjava/protocol/impl/clients/OFClient.java
new file mode 100644 (file)
index 0000000..f7b4baf
--- /dev/null
@@ -0,0 +1,40 @@
+/*\r
+ * Copyright (c) 2014 Pantheon Technologies s.r.o. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.openflowjava.protocol.impl.clients;\r
+\r
+import com.google.common.util.concurrent.SettableFuture;\r
+\r
+/**\r
+ * Unifying interface for simple clients / switch simulators\r
+ * \r
+ * @author michal.polkorab\r
+ */\r
+public interface OFClient extends Runnable {\r
+\r
+    /**\r
+     * @return the isOnlineFuture which is set when client is started\r
+     */\r
+    public SettableFuture<Boolean> getIsOnlineFuture();\r
+\r
+    /**\r
+     * @return the scenarioDone when scenario is successfully finished\r
+     */\r
+    public SettableFuture<Boolean> getScenarioDone();\r
+\r
+    /**\r
+     * @param scenario list of desired actions\r
+     */\r
+    public void setScenarioHandler(ScenarioHandler scenario);\r
+\r
+    /**\r
+     * @param securedClient true is client should use encrypted communication,\r
+     * false otherwise\r
+     */\r
+    public void setSecuredClient(boolean securedClient);\r
+}
\ No newline at end of file
index 72ef9d435c86561b5ff7cd0df28a461264bbadc9..e31c36740ffaf2dafcba42256a7377755ca57fd9 100644 (file)
@@ -27,7 +27,7 @@ import com.google.common.util.concurrent.SettableFuture;
  *
  * @author michal.polkorab
  */
-public class SimpleClient extends Thread {
+public class SimpleClient implements OFClient {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(SimpleClient.class);
     private final String host;
@@ -98,9 +98,7 @@ public class SimpleClient extends Thread {
         return group.shutdownGracefully();
     }
 
-    /**
-     * @param securedClient
-     */
+    @Override
     public void setSecuredClient(boolean securedClient) {
         this.securedClient = securedClient;
     }
@@ -131,27 +129,20 @@ public class SimpleClient extends Thread {
             sc = new SimpleClient(host, port);
             sc.setSecuredClient(Boolean.parseBoolean(args[2]));
         }
-        sc.start();
-        
+        sc.run();
     }
-    
-    /**
-     * @return the isOnlineFuture
-     */
+
+    @Override
     public SettableFuture<Boolean> getIsOnlineFuture() {
         return isOnlineFuture;
     }
-    
-    /**
-     * @return the scenarioDone
-     */
+
+    @Override
     public SettableFuture<Boolean> getScenarioDone() {
         return scenarioDone;
     }
-    
-    /**
-     * @param scenario list of wanted actions
-     */
+
+    @Override
     public void setScenarioHandler(ScenarioHandler scenario) {
         this.scenarioHandler = scenario;
     }
index 1d74bc0dce336d92637076485f57a0052a6dcb5d..c44a660cd08de933c82a95ac4b5cc647f1d80de0 100644 (file)
@@ -11,7 +11,7 @@ package org.opendaylight.openflowjava.protocol.impl.clients;
 
 import io.netty.channel.ChannelInitializer;
 import io.netty.channel.ChannelPipeline;
-import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
 import io.netty.handler.ssl.SslHandler;
 
 import javax.net.ssl.SSLEngine;
@@ -22,7 +22,7 @@ import com.google.common.util.concurrent.SettableFuture;
  * 
  * @author michal.polkorab
  */
-public class SimpleClientInitializer extends ChannelInitializer<SocketChannel> {
+public class SimpleClientInitializer extends ChannelInitializer<NioSocketChannel> {
     
     private SettableFuture<Boolean> isOnlineFuture;
     private boolean secured;
@@ -38,7 +38,7 @@ public class SimpleClientInitializer extends ChannelInitializer<SocketChannel> {
     }
 
     @Override
-    public void initChannel(SocketChannel ch) throws Exception {
+    public void initChannel(NioSocketChannel ch) throws Exception {
         ChannelPipeline pipeline = ch.pipeline();
         if (secured) {
             SSLEngine engine = ClientSslContextFactory.getClientContext()
diff --git a/simple-client/src/main/java/org/opendaylight/openflowjava/protocol/impl/clients/UdpSimpleClient.java b/simple-client/src/main/java/org/opendaylight/openflowjava/protocol/impl/clients/UdpSimpleClient.java
new file mode 100644 (file)
index 0000000..685dbd2
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2014 Pantheon Technologies s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowjava.protocol.impl.clients;
+
+import io.netty.bootstrap.Bootstrap;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.nio.NioDatagramChannel;
+import io.netty.util.concurrent.Future;
+
+import java.net.InetAddress;
+import java.util.concurrent.ExecutionException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.util.concurrent.SettableFuture;
+
+/**
+ * Simple client for testing purposes
+ *
+ * @author michal.polkorab
+ */
+public class UdpSimpleClient implements OFClient {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(UdpSimpleClient.class);
+    private final String host;
+    private final int port;
+    private EventLoopGroup group;
+    private SettableFuture<Boolean> isOnlineFuture;
+    private SettableFuture<Boolean> scenarioDone;
+    private UdpSimpleClientInitializer clientInitializer;
+    private ScenarioHandler scenarioHandler;
+    
+    /**
+     * Constructor of class
+     *
+     * @param host address of host
+     * @param port host listening port
+     */
+    public UdpSimpleClient(String host, int port) {
+        this.host = host;
+        this.port = port;
+        init();
+    }
+
+    private void init() {
+        isOnlineFuture = SettableFuture.create();
+        scenarioDone = SettableFuture.create();
+    }
+    
+    /**
+     * Starting class of {@link UdpSimpleClient}
+     */
+    @Override
+    public void run() {
+        group = new NioEventLoopGroup();
+        clientInitializer = new UdpSimpleClientInitializer(isOnlineFuture);
+        clientInitializer.setScenario(scenarioHandler);
+        try {
+            Bootstrap b = new Bootstrap();
+            b.group(group)
+                .channel(NioDatagramChannel.class)
+                .option(ChannelOption.SO_BROADCAST, false)
+                .handler(clientInitializer);
+
+            b.connect(host, port).sync();
+
+            synchronized (scenarioHandler) {
+                LOGGER.debug("WAITING FOR SCENARIO");
+                scenarioHandler.wait();
+            }
+        } catch (Exception ex) {
+            LOGGER.error(ex.getMessage(), ex);
+        } finally {
+            LOGGER.debug("shutting down");
+            try {
+                group.shutdownGracefully().get();
+                LOGGER.debug("shutdown succesful");
+            } catch (InterruptedException | ExecutionException e) {
+                LOGGER.error(e.getMessage(), e);
+            }
+        }
+        scenarioDone.set(true);
+    }
+
+    /**
+     * @return close future
+     */
+    public Future<?> disconnect() {
+        LOGGER.debug("disconnecting client");
+        return group.shutdownGracefully();
+    }
+
+    /**
+     * Sets up {@link UdpSimpleClient} and fires run()
+     *
+     * @param args
+     * @throws Exception
+     */
+    public static void main(String[] args) throws Exception {
+        String host;
+        int port;
+        UdpSimpleClient sc;
+        if (args.length != 2) {
+            LOGGER.error("Usage: " + UdpSimpleClient.class.getSimpleName()
+                    + " <host> <port>");
+            LOGGER.error("Trying to use default setting.");
+            InetAddress ia = InetAddress.getLocalHost();
+            InetAddress[] all = InetAddress.getAllByName(ia.getHostName());
+            host = all[0].getHostAddress();
+            port = 6633;
+            sc = new UdpSimpleClient(host, port);
+        } else {
+            host = args[0];
+            port = Integer.parseInt(args[1]);
+            sc = new UdpSimpleClient(host, port);
+        }
+        sc.run();
+        
+    }
+
+    @Override
+    public SettableFuture<Boolean> getIsOnlineFuture() {
+        return isOnlineFuture;
+    }
+
+    @Override
+    public SettableFuture<Boolean> getScenarioDone() {
+        return scenarioDone;
+    }
+
+    @Override
+    public void setScenarioHandler(ScenarioHandler scenario) {
+        this.scenarioHandler = scenario;
+    }
+
+    @Override
+    public void setSecuredClient(boolean securedClient) {
+        // TODO: Finish implementation when DTLS is supported
+    }
+}
\ No newline at end of file
diff --git a/simple-client/src/main/java/org/opendaylight/openflowjava/protocol/impl/clients/UdpSimpleClientFramer.java b/simple-client/src/main/java/org/opendaylight/openflowjava/protocol/impl/clients/UdpSimpleClientFramer.java
new file mode 100644 (file)
index 0000000..d5f8e7b
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2014 Pantheon Technologies s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+
+package org.opendaylight.openflowjava.protocol.impl.clients;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.socket.DatagramPacket;
+import io.netty.handler.codec.MessageToMessageDecoder;
+
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class for decoding incoming udp messages into message frames.
+ *
+ * @author michal.polkorab
+ */
+public class UdpSimpleClientFramer extends MessageToMessageDecoder<DatagramPacket> {
+
+    /** Length of OpenFlow 1.3 header */
+    public static final byte LENGTH_OF_HEADER = 8;
+    private static final byte LENGTH_INDEX_IN_HEADER = 2;
+    private static final Logger LOGGER = LoggerFactory.getLogger(UdpSimpleClientFramer.class);
+
+    /**
+     * Constructor of class.
+     */
+    public UdpSimpleClientFramer() {
+        LOGGER.trace("Creating OFFrameDecoder");
+    }
+
+    @Override
+    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+        LOGGER.warn("Unexpected exception from downstream.", cause);
+        ctx.close();
+    }
+
+    @Override
+    protected void decode(ChannelHandlerContext chc, DatagramPacket msg, List<Object> list) throws Exception {
+        ByteBuf bb = msg.content();
+        if (bb.readableBytes() < LENGTH_OF_HEADER) {
+            LOGGER.debug("skipping bb - too few data for header: " + bb.readableBytes());
+            return;
+        }
+
+        int length = bb.getUnsignedShort(bb.readerIndex() + LENGTH_INDEX_IN_HEADER);
+        if (bb.readableBytes() < length) {
+            LOGGER.debug("skipping bb - too few data for msg: " +
+                    bb.readableBytes() + " < " + length);
+            return;
+        }
+        LOGGER.debug("OF Protocol message received, type:{}", bb.getByte(bb.readerIndex() + 1));
+
+        ByteBuf messageBuffer = bb.slice(bb.readerIndex(), length);
+        list.add(messageBuffer);
+        messageBuffer.retain();
+        bb.skipBytes(length);
+    }
+}
\ No newline at end of file
diff --git a/simple-client/src/main/java/org/opendaylight/openflowjava/protocol/impl/clients/UdpSimpleClientInitializer.java b/simple-client/src/main/java/org/opendaylight/openflowjava/protocol/impl/clients/UdpSimpleClientInitializer.java
new file mode 100644 (file)
index 0000000..cd7a8a8
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014 Pantheon Technologies s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+
+package org.opendaylight.openflowjava.protocol.impl.clients;
+
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.socket.nio.NioDatagramChannel;
+
+import com.google.common.util.concurrent.SettableFuture;
+
+/** Initializes udp pipeline
+ * 
+ * @author michal.polkorab
+ */
+public class UdpSimpleClientInitializer extends ChannelInitializer<NioDatagramChannel> {
+    
+    private SettableFuture<Boolean> isOnlineFuture;
+    private ScenarioHandler scenarioHandler;
+
+    /**
+     * @param isOnlineFuture future notifier of connected channel
+     */
+    public UdpSimpleClientInitializer(SettableFuture<Boolean> isOnlineFuture) {
+        this.isOnlineFuture = isOnlineFuture;
+    }
+
+    @Override
+    public void initChannel(NioDatagramChannel ch) throws Exception {
+        ChannelPipeline pipeline = ch.pipeline();
+        SimpleClientHandler simpleClientHandler = new SimpleClientHandler(isOnlineFuture, scenarioHandler);
+        simpleClientHandler.setScenario(scenarioHandler);
+        pipeline.addLast("framer", new UdpSimpleClientFramer());
+        pipeline.addLast("handler", simpleClientHandler);
+        isOnlineFuture = null;
+    }
+
+    /**
+     * @param scenarioHandler handler of scenario events
+     */
+    public void setScenario(ScenarioHandler scenarioHandler) {
+        this.scenarioHandler = scenarioHandler;
+    }
+}
\ No newline at end of file