/**
* Copyright 2011, Big Switch Networks, Inc.
* Originally created by David Erickson, Stanford University
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
**/
package net.floodlightcontroller.core.internal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import org.projectfloodlight.openflow.protocol.OFFactories;
import org.projectfloodlight.openflow.protocol.OFFactory;
import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFMessageReader;
import org.projectfloodlight.openflow.protocol.OFVersion;
/**
* Decode an openflow message from a channel, for use in a netty pipeline.
*
* @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
*/
public class OFMessageDecoder extends ByteToMessageDecoder {
private OFMessageReader<OFMessage> reader;
public OFMessageDecoder() {
setReader();
}
public OFMessageDecoder(OFVersion version) {
setVersion(version);
setReader();
}
private void setReader() {
reader = OFFactories.getGenericReader();
}
public void setVersion(OFVersion version) {
OFFactory factory = OFFactories.getFactory(version);
this.reader = factory.getReader();
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
if (!ctx.channel().isActive()) {
// In testing, I see decode being called AFTER decode last.
// This check avoids that from reading corrupted frames
return;
}
// Note(andiw): netty4 adds support for more efficient handling of lists messages in the
// pipeline itself.
// Instead of constructing a list of messages here, we could also just add the individual
// messages to the "out" list provided by netty. This would require changing all the handlers
// in the pipeline to accept "OFMessage" instead of "Iterable<OFMessage>". Probably
// a good idea, but left for a future cleanup.
OFMessage singleMessage = null;
List<OFMessage> list = null;
boolean first = true;
for (;;) {
OFMessage message = reader.readFrom(in);
if (message == null) {
break;
}
if (first) {
// first message read
singleMessage = message;
first = false;
} else {
// more messages read, use the list
if (list == null) {
list = new ArrayList<>();
list.add(singleMessage);
singleMessage = null;
}
list.add(message);
}
}
if (list != null) {
out.add(list);
} else if (singleMessage != null) {
out.add(Collections.singletonList(singleMessage));
}
}
}