package net.varkhan.serv.p2p.message.protocol; import net.varkhan.serv.p2p.message.MesgPayload; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** * <b></b>. * <p/> * * @author varkhan * @date 2/24/11 * @time 1:06 AM */ public class BinaryEnvelope { protected byte type; protected long flags=0; protected String srcId; protected String dstId; protected String method; protected long sequence=-1; protected MesgPayload message; protected InputStream dataIS=null; // protected OutputStream dataOS = null; protected byte[] data =null; protected int dataBeg, dataLen; private static final int msg_seqId_len=8; private static final int msg_flags_len=8; public static final byte CALL=1; public static final byte REPL=2; public static final byte PING=8; public BinaryEnvelope(byte[] data) throws IOException { this(data, 0, data.length); } public BinaryEnvelope(byte type, String src, String dst, String method, long sequence, MesgPayload message) { this.type = type; this.srcId = src; this.dstId = dst; this.method = method; this.sequence = sequence; this.message=message; } public BinaryEnvelope(byte[] data, int beg, int len) throws IOException { int hdr = readHeader(data, beg, len); BinaryPayload message = new BinaryPayload(); message.setData(data,beg+hdr,len-hdr); this.message = message; } public BinaryEnvelope(InputStream data) throws IOException { readHeader(data); BinaryPayload message = new BinaryPayload(); message.setData(data); this.message = message; } public byte type() { return type; } public void send(OutputStream out) throws IOException { writeHeader(out); // private void writeData(OutputStream data) throws IOException { // if(this.data!=null) { // data.write(this.data,this.dataBeg,this.dataLen); // } // if(this.dataIS!=null) { // byte[] buf = new byte[4096]; // int len; // while((len=this.dataIS.read(buf)) != -1) { // data.write(buf,0,len); // } // } // } message.readData(0,out,Integer.MAX_VALUE); } public String method() { return method; } public long sequence() { return sequence; } public MesgPayload message() { return message; } public String srcId() { return srcId; } public String dstId() { return dstId; } /********************************************************************************** ** Message format parsing **/ /** * Initializes a message from a data stream * * @param data the input stream containing the complete message data * @throws java.io.IOException on a data read error or an invalid message format */ private void readHeader(InputStream data) throws IOException { byte[] buf = new byte[256]; char[] str = new char[256]; int cnt = 0; int b; // Read message type cnt = data.read(); if(cnt==-1) throw new IOException("Invalid message format (type)"); type = (byte)cnt; // Read message source cnt = data.read(); if(cnt==-1) throw new IOException("Invalid message format (src)"); b = data.read(buf,0,cnt); if(b<cnt) throw new IOException("Invalid message format (src)"); for(int i=0; i<cnt; i++) str[i] = (char) (buf[i]&0x7F); this.srcId = String.valueOf(str,0,cnt); // Read message destination cnt = data.read(); if(cnt==-1) throw new IOException("Invalid message format (dst)"); b = data.read(buf,0,cnt); if(b<cnt) throw new IOException("Invalid message format (dst)"); for(int i=0; i<cnt; i++) str[i] = (char) (buf[i]&0x7F); this.dstId = String.valueOf(str,0,cnt); // Read procedure id cnt = data.read(); if(cnt==-1) throw new IOException("Invalid message format (method)"); b = data.read(buf,0,cnt); if(b<cnt) throw new IOException("Invalid message format (method)"); for(int i=0; i<cnt; i++) str[i] = (char) (buf[i]&0x7F); this.method= String.valueOf(str,0,cnt); // Read sequence id b = data.read(buf,0,msg_seqId_len); if(b<msg_seqId_len) throw new IOException("Invalid message format (sequence)"); // Read N bytes, big-endian long seqId = 0; for(int i=(msg_seqId_len-1); i>=0; i--) seqId += (buf[i]&0x7F)<<(i<<3); this.sequence= seqId; // Read flags array b = data.read(buf,0,msg_seqId_len); if(b<msg_flags_len) throw new IOException("Invalid message format (sequence)"); // Read N bytes, big-endian long flags = 0; for(int i=(msg_flags_len-1); i>=0; i--) flags += (buf[i]&0xFF)<<(i<<3); this.flags = flags; } /** * Initializes a message from a byte array * * @param data the byte array containing the message data * @param beg the start position of message data in the array * @param len the length (number of bytes) of message data available * @return the number of bytes read from the byte array * @throws java.io.IOException on a data read error or an invalid message format */ private int readHeader(byte[] data, int beg, int len) throws IOException { char[] str = new char[256]; int pos = beg; int end = len + beg; int cnt; // Read message type if(pos>=end) throw new IOException("Invalid message format (type)"); cnt = data[pos++]&0xFF; type = (byte)cnt; // Read message source if(pos>=end) throw new IOException("Invalid message format (src)"); cnt = data[pos++]&0xFF; if(pos+cnt>end) throw new IOException("Invalid message format (src)"); for(int i=0; i<cnt; i++, pos++) str[i] = (char) (data[pos]&0x7F); this.srcId = String.valueOf(str,0,cnt); // Read message destination if(pos>=end) throw new IOException("Invalid message format (dst)"); cnt = data[pos++]&0xFF; if(pos+cnt>end) throw new IOException("Invalid message format (dst)"); for(int i=0; i<cnt; i++, pos++) str[i] = (char) (data[pos]&0x7F); this.dstId = String.valueOf(str,0,cnt); // Read procedure id if(pos>=end) throw new IOException("Invalid message format (method)"); cnt = data[pos++]&0xFF; if(pos+cnt>end) throw new IOException("Invalid message format (method)"); for(int i=0; i<cnt; i++, pos++) str[i] = (char) (data[pos]&0x7F); this.method= String.valueOf(str,0,cnt); // Read sequence id if(pos+msg_seqId_len>end) throw new IOException("Invalid message format (sequence)"); // Read N bytes, big-endian long seqId = 0; for(int i=(msg_seqId_len-1); i>=0; i--) seqId += (data[pos+i]&0xFF)<<(i<<3); this.sequence= seqId; pos += msg_seqId_len; // Read flags array if(pos+msg_seqId_len>end) throw new IOException("Invalid message format (sequence)"); // Read N bytes, big-endian long flags = 0; for(int i=(msg_flags_len-1); i>=0; i--) flags += (data[pos+i]&0xFF)<<(i<<3); this.flags = flags; pos += msg_flags_len; return pos-beg; } private int headerLength() { return 1+1+srcId.length()+1+dstId.length()+1+method.length()+msg_seqId_len+msg_flags_len; } private void writeHeader(OutputStream data) throws IOException { byte[] buf = new byte[headerLength()]; int pos = 0; // Write message type buf[pos++] = type; // Write message source buf[pos++] = (byte) srcId.length(); for(int i=0; i<srcId.length(); i++, pos++) buf[pos] = (byte) (0x7F & srcId.charAt(i)); // Write message destination buf[pos++] = (byte) dstId.length(); for(int i=0; i<dstId.length(); i++, pos++) buf[pos] = (byte) (0x7F & dstId.charAt(i)); // Write procedure id buf[pos++] = (byte) method.length(); for(int i=0; i<method.length(); i++, pos++) buf[pos] = (byte) (0x7F & method.charAt(i)); // Write sequence id, big-endian for(int i=0; i<msg_seqId_len; i++) buf[pos+i] = (byte) ((this.sequence>>>(i<<3))&0xFF); pos += msg_seqId_len; // Write flags array, big-endian for(int i=0; i<msg_flags_len; i++) buf[pos+i] = (byte) ((this.flags>>>(i<<3))&0xFF); pos += msg_flags_len; data.write(buf,0,pos); } // private int writeHeader(byte[] buf, int beg, int len) throws IOException { // int pos = beg; // // Write message type // buf[pos++] = (byte) type.ordinal(); // // Write message source // buf[pos++] = (byte) srcId.length(); // for(int i=0; i<srcId.length(); i++, pos++) buf[pos] = (byte) (0x7F & srcId.charAt(i)); // // Write message destination // buf[pos++] = (byte) dstId.length(); // for(int i=0; i<dstId.length(); i++, pos++) buf[pos] = (byte) (0x7F & dstId.charAt(i)); // // Write procedure id // buf[pos++] = (byte) rpcId.length(); // for(int i=0; i<rpcId.length(); i++, pos++) buf[pos] = (byte) (0x7F & rpcId.charAt(i)); // // Write sequence id, big-endian // for(int i=0; i<msg_seqId_len; i++) buf[pos+i] = (byte) ((this.seqId>>>(i<<3))&0xFF); // pos += msg_seqId_len; // // Write flags array, big-endian // for(int i=0; i<msg_flags_len; i++) buf[pos+i] = (byte) ((this.flags>>>(i<<3))&0xFF); // pos += msg_flags_len; // return pos-beg; // } // private void writeData(OutputStream data) throws IOException { // if(this.data!=null) { // data.write(this.data,this.dataBeg,this.dataLen); // } // if(this.dataIS!=null) { // byte[] buf = new byte[4096]; // int len; // while((len=this.dataIS.read(buf)) != -1) { // data.write(buf,0,len); // } // } // } // private int writeData(byte[] buf, int beg, int len) throws IOException { // int pos = beg; // if(this.data!=null) { // System.arraycopy(data,dataBeg,buf,pos,dataLen); // pos += dataLen; // } // if(this.dataIS!=null) { // int cnt; // while((cnt=this.dataIS.read(buf,pos,len)) != -1) { // pos += cnt; // } // } // return pos-beg; // } }