package org.fastcatsearch.transport; import java.io.IOException; import java.io.StreamCorruptedException; import org.jboss.netty.buffer.ChannelBuffer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MessageProtocol { private static Logger logger = LoggerFactory.getLogger(MessageProtocol.class); //MESSAGE_PREFIX public static final int HEADER_SIZE = 2 + 1 + 4 + 8 + 1; //HEADER(2) + type(1) + data-length(4) + requestId(8) + status(1) private static byte[] handShakeRequestData = new byte[]{'R','E','Q','?'}; private static byte[] handShakeEstablishedData = new byte[]{'F','I','N','E'}; private static byte[] HEADER = new byte[]{'F','S'}; //FastcatSearch private static byte[] EOM = new byte[]{'F','S','E','M'}; private static ChannelBuffer handshakeRequestBuffer; private static ChannelBuffer handshakeEstablishedBuffer; // static{ // handshakeRequestBuffer = ChannelBuffers.buffer(HEADER_SIZE + handShakeRequestData.length); // writeHeader(handshakeRequestBuffer, handShakeRequestData.length); // // handshakeEstablishedBuffer = ChannelBuffers.buffer(HEADER_SIZE + handShakeEstablishedData.length); // writeHeader(handshakeEstablishedBuffer, handShakeEstablishedData.length); // } // public static void writeHeader(ChannelBuffer buffer, int dataLength){ // buffer.writeBytes(HEADER); // buffer.writeInt(dataLength); // buffer.writeByte(1); // buffer.writeByte(0); // } // public static ChannelBuffer newHandshakeRequest(){ // ChannelBuffer buffer = handshakeRequestBuffer.copy(); // writeHeader(buffer, handShakeRequestData.length); // buffer.writeBytes(handShakeRequestData); // return buffer; // } // public static ChannelBuffer newHandshakeEstablished(){ // ChannelBuffer buffer = handshakeEstablishedBuffer.copy(); // writeHeader(buffer, handShakeEstablishedData.length); // buffer.writeBytes(handShakeEstablishedData); // return buffer; // } public static void main(String[] args) { for (int i = 0; i < HEADER.length; i++) { System.out.println(HEADER[i]+", "+(char)HEADER[i]); } } // public static boolean readHeader(StreamInput input){ // byte[] buf = new byte[HEADER.length]; // if(readFully(input, buf, buf.length) != HEADER.length){ // return false; // } // // if(!isValidHeader(buf)){ // logger.error("메시지 헤더가 올바르지 않습니다. {}", (char)buf[0]+", "+(char)buf[1]+", "+(char)buf[2]+", "+(char)buf[3]); // return false; // } // // return true; // } public static void writeHeader(ChannelBuffer buffer, byte type, long requestId, byte status) { int index = buffer.readerIndex(); buffer.setByte(index, HEADER[0]); index += 1; buffer.setByte(index, HEADER[1]); index += 1; buffer.setByte(index, type); index += 1; buffer.setInt(index, buffer.readableBytes() - 7); index += 4; buffer.setLong(index, requestId); index += 8; buffer.setByte(index, status); } private static boolean isValidHeader(byte[] buf) { for (int i = 0; i < HEADER.length; i++) { if(HEADER[i] != buf[i]){ return false; } } return true; } private static boolean isValidEOM(byte[] buf) { for (int i = 0; i < EOM.length; i++) { if(EOM[i] != buf[i]){ return false; } } return true; } // private static int readFully(StreamInput input, byte[] buf, int len){ // int nread = 0; // // try { // while(nread < len){ // nread += input.readBytes(buf, 0, len); // } // } catch (IOException e) { // logger.error("데이터를 읽는중 에러발생.", e); // } // // return nread; // } // public static Message readMessageClass(Input input) { // try { // int len = input.readVariableByte(); // char[] className = input.readAChars(len); // return (Message)IRClassLoader.getInstance().loadObject(new String(className)); // } catch (IOException e) { // logger.error("Input 에러.", e); // } // return null; // } // public static void writeMessageClass(Output output, Message message) { // try { // char[] className = message.getClass().getName().toCharArray(); // output.writeVariableByte(className.length); // output.writeAChars(className, 0, className.length); // } catch (IOException e) { // logger.error("Output 에러.", e); // } // } // public static boolean writeEndOfMessage(Output output) { // try { // output.writeBytes(EOM); // } catch (IOException e) { // logger.error("EOM기록중 에러발생.", e); // return false; // } // return true; // } public static boolean writeHandshake1(ChannelBuffer output){ logger.debug("HandShake1 기록!"); output.writeBytes(handShakeRequestData); logger.debug("HandShake1 기록완료!"); return true; } public static boolean writeHandshake2(ChannelBuffer output){ logger.debug("HandShake2 기록!"); output.writeBytes(handShakeEstablishedData); logger.debug("HandShake2 기록완료!"); return true; } public static boolean readHandshake1(ChannelBuffer input){ logger.debug("HandShake1 읽기!"); for (int i = 0; i < handShakeRequestData.length; i++) { if(handShakeRequestData[i] != input.readByte()){ return false; } } logger.debug("HandShake1 읽기완료!"); return true; } public static boolean readHandshake2(ChannelBuffer input){ logger.debug("HandShake2 읽기!"); for (int i = 0; i < handShakeEstablishedData.length; i++) { if(handShakeEstablishedData[i] != input.readByte()){ return false; } } logger.debug("HandShake2 읽기완료!"); return true; } // public static boolean readEndOfMessage(Input input) { // byte[] buf = new byte[EOM.length]; // if(readFully(input, buf, buf.length) != EOM.length){ // return false; // } // // if(!isValidEOM(buf)){ // logger.error("메시지 EOM이 올바르지 않습니다.{}", (char)buf[0]+", "+(char)buf[1]+", "+(char)buf[2]+", "+(char)buf[3]); // return false; // } // // return true; // // } public static boolean isBufferReady(ChannelBuffer buffer, int readerIndex) throws IOException { //prefix + version + status + dataLength int readAhead = 0; // logger.debug("readerIndex = {}, buffer={}", readerIndex, buffer); // logger.debug("{}:{}", buffer.getByte(readerIndex), HEADER[0]); // logger.debug("{}:{}", buffer.getByte(readerIndex+1), HEADER[1]); if (buffer.getByte(readerIndex) != HEADER[0] || buffer.getByte(readerIndex + 1) != HEADER[1]) { throw new StreamCorruptedException("Invalid protocol data format"); } readAhead += 2; int type = buffer.getByte(readerIndex + readAhead); readAhead += 1; int dataLength = buffer.getInt(readerIndex + readAhead); readAhead += 4; if (dataLength <= 0) { throw new StreamCorruptedException("Invalid data length : "+dataLength); } long requestId = buffer.getLong(readerIndex + readAhead); readAhead += 8; int status = buffer.getByte(readerIndex + readAhead); readAhead += 1; // jvm max heap사이즈를 고려하여 max사이즈를 넘지 않도록한다. // if (dataLength > MAX_ALLOWED_SIZE) { // throw new Exception // } if (buffer.readableBytes() < 7 + dataLength) { // logger.debug("버퍼가 아직은 모자람.{} < {}", buffer.readableBytes(), dataLength + 7); return false; } // logger.debug("버퍼가 충분함.{} : {}", buffer.readableBytes(), dataLength + 7); return true; } }