/*
* Copyright 2014 NAVER Corp.
*
* 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 com.navercorp.pinpoint.rpc.codec;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.frame.FrameDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.navercorp.pinpoint.rpc.client.WriteFailFutureListener;
import com.navercorp.pinpoint.rpc.packet.ClientClosePacket;
import com.navercorp.pinpoint.rpc.packet.ControlHandshakePacket;
import com.navercorp.pinpoint.rpc.packet.ControlHandshakeResponsePacket;
import com.navercorp.pinpoint.rpc.packet.PacketType;
import com.navercorp.pinpoint.rpc.packet.PingPacket;
import com.navercorp.pinpoint.rpc.packet.PongPacket;
import com.navercorp.pinpoint.rpc.packet.RequestPacket;
import com.navercorp.pinpoint.rpc.packet.ResponsePacket;
import com.navercorp.pinpoint.rpc.packet.SendPacket;
import com.navercorp.pinpoint.rpc.packet.ServerClosePacket;
import com.navercorp.pinpoint.rpc.packet.stream.StreamClosePacket;
import com.navercorp.pinpoint.rpc.packet.stream.StreamCreateFailPacket;
import com.navercorp.pinpoint.rpc.packet.stream.StreamCreatePacket;
import com.navercorp.pinpoint.rpc.packet.stream.StreamCreateSuccessPacket;
import com.navercorp.pinpoint.rpc.packet.stream.StreamPingPacket;
import com.navercorp.pinpoint.rpc.packet.stream.StreamPongPacket;
import com.navercorp.pinpoint.rpc.packet.stream.StreamResponsePacket;
/**
* @author emeroad
* @author koo.taejin
*/
public class PacketDecoder extends FrameDecoder {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final WriteFailFutureListener pongWriteFutureListener = new WriteFailFutureListener(logger, "pong write fail.", "pong write success.");
@Override
protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception {
if (buffer.readableBytes() < 2) {
return null;
}
buffer.markReaderIndex();
final short packetType = buffer.readShort();
switch (packetType) {
case PacketType.APPLICATION_SEND:
return readSend(packetType, buffer);
case PacketType.APPLICATION_REQUEST:
return readRequest(packetType, buffer);
case PacketType.APPLICATION_RESPONSE:
return readResponse(packetType, buffer);
case PacketType.APPLICATION_STREAM_CREATE:
return readStreamCreate(packetType, buffer);
case PacketType.APPLICATION_STREAM_CLOSE:
return readStreamClose(packetType, buffer);
case PacketType.APPLICATION_STREAM_CREATE_SUCCESS:
return readStreamCreateSuccess(packetType, buffer);
case PacketType.APPLICATION_STREAM_CREATE_FAIL:
return readStreamCreateFail(packetType, buffer);
case PacketType.APPLICATION_STREAM_RESPONSE:
return readStreamData(packetType, buffer);
case PacketType.APPLICATION_STREAM_PING:
return readStreamPing(packetType, buffer);
case PacketType.APPLICATION_STREAM_PONG:
return readStreamPong(packetType, buffer);
case PacketType.CONTROL_CLIENT_CLOSE:
return readControlClientClose(packetType, buffer);
case PacketType.CONTROL_SERVER_CLOSE:
return readControlServerClose(packetType, buffer);
case PacketType.CONTROL_PING:
PingPacket pingPacket = (PingPacket) readPing(packetType, buffer);
if (pingPacket == PingPacket.PING_PACKET) {
sendPong(channel);
// just drop ping
return null;
}
return pingPacket;
case PacketType.CONTROL_PONG:
logger.debug("receive pong. {}", channel);
readPong(packetType, buffer);
// just also drop pong.
return null;
case PacketType.CONTROL_HANDSHAKE:
return readEnableWorker(packetType, buffer);
case PacketType.CONTROL_HANDSHAKE_RESPONSE:
return readEnableWorkerConfirm(packetType, buffer);
}
logger.error("invalid packetType received. packetType:{}, channel:{}", packetType, channel);
channel.close();
return null;
}
private void sendPong(Channel channel) {
// a "pong" responds to a "ping" automatically.
logger.debug("received ping. sending pong. {}", channel);
ChannelFuture write = channel.write(PongPacket.PONG_PACKET);
write.addListener(pongWriteFutureListener);
}
private Object readControlClientClose(short packetType, ChannelBuffer buffer) {
return ClientClosePacket.readBuffer(packetType, buffer);
}
private Object readControlServerClose(short packetType, ChannelBuffer buffer) {
return ServerClosePacket.readBuffer(packetType, buffer);
}
private Object readPong(short packetType, ChannelBuffer buffer) {
return PongPacket.readBuffer(packetType, buffer);
}
private Object readPing(short packetType, ChannelBuffer buffer) {
return PingPacket.readBuffer(packetType, buffer);
}
private Object readSend(short packetType, ChannelBuffer buffer) {
return SendPacket.readBuffer(packetType, buffer);
}
private Object readRequest(short packetType, ChannelBuffer buffer) {
return RequestPacket.readBuffer(packetType, buffer);
}
private Object readResponse(short packetType, ChannelBuffer buffer) {
return ResponsePacket.readBuffer(packetType, buffer);
}
private Object readStreamCreate(short packetType, ChannelBuffer buffer) {
return StreamCreatePacket.readBuffer(packetType, buffer);
}
private Object readStreamCreateSuccess(short packetType, ChannelBuffer buffer) {
return StreamCreateSuccessPacket.readBuffer(packetType, buffer);
}
private Object readStreamCreateFail(short packetType, ChannelBuffer buffer) {
return StreamCreateFailPacket.readBuffer(packetType, buffer);
}
private Object readStreamData(short packetType, ChannelBuffer buffer) {
return StreamResponsePacket.readBuffer(packetType, buffer);
}
private Object readStreamPong(short packetType, ChannelBuffer buffer) {
return StreamPongPacket.readBuffer(packetType, buffer);
}
private Object readStreamPing(short packetType, ChannelBuffer buffer) {
return StreamPingPacket.readBuffer(packetType, buffer);
}
private Object readStreamClose(short packetType, ChannelBuffer buffer) {
return StreamClosePacket.readBuffer(packetType, buffer);
}
private Object readEnableWorker(short packetType, ChannelBuffer buffer) {
return ControlHandshakePacket.readBuffer(packetType, buffer);
}
private Object readEnableWorkerConfirm(short packetType, ChannelBuffer buffer) {
return ControlHandshakeResponsePacket.readBuffer(packetType, buffer);
}
}