package com.dianping.pigeon.remoting.netty.codec; import com.dianping.pigeon.log.LoggerLoader; import com.dianping.pigeon.remoting.common.codec.CodecConfig; import com.dianping.pigeon.log.Logger; import com.dianping.pigeon.remoting.common.codec.CodecConfigFactory; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.DynamicChannelBuffer; import org.jboss.netty.channel.*; import java.net.InetSocketAddress; import java.util.zip.Adler32; import static org.jboss.netty.channel.Channels.write; /** * @author qi.yin * 2016/06/14 下午11:40. */ public class Crc32Handler extends SimpleChannelHandler { private static final Logger logger = LoggerLoader.getLogger(Crc32Handler.class); private static ThreadLocal<Adler32> adler32s = new ThreadLocal<Adler32>(); private CodecConfig codecConfig; public Crc32Handler(CodecConfig codecConfig) { this.codecConfig = codecConfig; } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { if (e.getMessage() == null || !(e.getMessage() instanceof CodecEvent)) { return; } CodecEvent codecEvent = (CodecEvent) e.getMessage(); if (codecEvent.isValid()) { if (codecEvent.isUnified()) { if (!doUnChecksum(e.getChannel(), codecEvent)) { codecEvent.setIsValid(false); } } } Channels.fireMessageReceived(ctx, codecEvent, e.getRemoteAddress()); } @Override public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { if (!(e instanceof MessageEvent)) { ctx.sendDownstream(e); return; } MessageEvent evt = (MessageEvent) e; if (!(evt.getMessage() instanceof CodecEvent)) { ctx.sendDownstream(evt); return; } CodecEvent codecEvent = (CodecEvent) evt.getMessage(); if (codecEvent.isUnified()) { ChannelBuffer buffer = doChecksum(e.getChannel(), codecEvent); codecEvent.setBuffer(buffer); write(ctx, evt.getFuture(), codecEvent, evt.getRemoteAddress()); } else { ctx.sendDownstream(e); } } private boolean doUnChecksum(Channel channel, CodecEvent codecEvent) { ChannelBuffer frame = codecEvent.getBuffer(); byte command = frame.getByte(frame.readerIndex() + CodecConstants._FRONT_COMMAND_LENGTH); if ((command & 0x80) == 0x80) { int frameLength = frame.readableBytes(); int dataLength = frameLength - CodecConstants._TAIL_LENGTH; ChannelBuffer buffer = frame.factory().getBuffer(dataLength); buffer.writeBytes(frame, frame.readerIndex(), dataLength); codecEvent.setIsChecksum(true); int checksum = (int) doChecksum0(buffer, dataLength); int _checksum = frame.getInt(dataLength); if (checksum == _checksum) { int totalLength = buffer.getInt(CodecConstants._HEAD_LENGTH); buffer.setInt(CodecConstants._HEAD_LENGTH, totalLength - CodecConstants._TAIL_LENGTH); codecEvent.setBuffer(buffer); } else { String host = ((InetSocketAddress) channel.getRemoteAddress()).getAddress().getHostAddress(); logger.error("Checksum failed. data from host:" + host); return false; } } return true; } private ChannelBuffer doChecksum(Channel channel, CodecEvent codecEvent) { ChannelBuffer frame = codecEvent.getBuffer(); boolean isChecksum = codecConfig.isChecksum(); int command = frame.getByte(CodecConstants._FRONT_COMMAND_LENGTH); int frameLength = frame.readableBytes(); if (isChecksum) { command = command | 0x80; //command frame.writerIndex(CodecConstants._FRONT_COMMAND_LENGTH); frame.writeByte(command); //totalLength frame.writeInt(frameLength - CodecConstants._FRONT_LENGTH_ + CodecConstants._TAIL_LENGTH); frame.writerIndex(frameLength); if (!(frame instanceof DynamicChannelBuffer)) { ChannelBuffer buffer = frame.factory().getBuffer(frameLength + CodecConstants._TAIL_LENGTH); buffer.writeBytes(frame, frame.readerIndex(), frameLength); frame = buffer; } long checksum = doChecksum0(frame, frameLength); frame.writeInt((int) checksum); } else { //command command = command & 0x7f; frame.writerIndex(CodecConstants._FRONT_COMMAND_LENGTH); frame.writeByte(command); frame.writerIndex(frameLength); } return frame; } private long doChecksum0(ChannelBuffer frame, int frameLength) { //checksum Adler32 adler32 = adler32s.get(); if (adler32 == null) { adler32 = new Adler32(); adler32s.set(adler32); } adler32.reset(); adler32.update(frame.array(), 0, frameLength); return adler32.getValue(); } }