com.csource.fastdht.ProtoCommon Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of wichell-common Show documentation
Show all versions of wichell-common Show documentation
common project com.wichell.wichell jar
The newest version!
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* FastDHT Java Client may be copied only under the terms of the GNU Lesser
* General Public License (LGPL).
* Please visit the FastDHT Home Page http://fastdht.csource.org/ for more detail.
**/
package com.csource.fastdht;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.util.Arrays;
/**
* protocol common functions
* @author Happy Fish / YuQing
* @version Version 1.03
*/
public class ProtoCommon
{
/**
* package header info
*/
public static class PkgHeader
{
public int body_len;
public int key_hash_code;
public int timestamp;
public int expires;
public byte cmd;
public byte keep_alive;
public byte status;
public PkgHeader()
{
}
public PkgHeader(byte status, int body_len)
{
this.status = status;
this.body_len = body_len;
}
}
/**
* package info
*/
public static class PkgInfo
{
public PkgHeader header;
public byte[] body;
public PkgInfo(PkgHeader header, byte[] body)
{
this.header = header;
this.body = body;
}
}
public static final byte FDHT_PROTO_CMD_QUIT = 10;
public static final byte FDHT_PROTO_CMD_SET = 11;
public static final byte FDHT_PROTO_CMD_INC = 12;
public static final byte FDHT_PROTO_CMD_GET = 13;
public static final byte FDHT_PROTO_CMD_DEL = 14;
public static final byte FDHT_PROTO_CMD_BATCH_SET = 15;
public static final byte FDHT_PROTO_CMD_BATCH_GET = 16;
public static final byte FDHT_PROTO_CMD_BATCH_DEL = 17;
public static final byte FDHT_PROTO_CMD_STAT = 18;
public static final byte FDHT_PROTO_CMD_GET_SUB_KEYS = 19;
public static final byte FDHT_PROTO_CMD_HEART_BEAT = 30;
public static final byte FDHT_PROTO_CMD_RESP = 40;
public static final int PROTO_HEADER_BODY_LEN_INDEX = 0;
public static final int PROTO_HEADER_KEY_HASH_CODE_INDEX = 4;
public static final int PROTO_HEADER_TIMESTAMP_INDEX = 8;
public static final int PROTO_HEADER_EXPIRES_INDEX = 12;
public static final int PROTO_HEADER_CMD_INDEX = 16;
public static final int PROTO_HEADER_KEEP_ALIVE_INDEX = 17;
public static final int PROTO_HEADER_STATUS_INDEX = 18;
public static final int FDHT_PROTO_PKG_HEADER_SIZE = 19;
public static final int FDHT_MAX_NAMESPACE_LEN = 64;
public static final int FDHT_MAX_OBJECT_ID_LEN = 128;
public static final int FDHT_MAX_SUB_KEY_LEN = 128;
public static final byte FDHT_FULL_KEY_SEPERATOR = 0x1;
public static final char FDHT_KEY_LIST_SEP_CHAR = FDHT_FULL_KEY_SEPERATOR;
public static final String FDHT_KEY_LIST_SEP_STR = String.valueOf(FDHT_KEY_LIST_SEP_CHAR);
public static final int FDHT_EXPIRES_NEVER = 0; //never timeout
public static final int FDHT_EXPIRES_NONE = -1; //invalid timeout, should ignore
public static final int FDHT_MAX_FULL_KEY_LEN = (FDHT_MAX_NAMESPACE_LEN + 1 +
FDHT_MAX_OBJECT_ID_LEN + 1 + FDHT_MAX_SUB_KEY_LEN);
private ProtoCommon()
{
}
/**
* pack header by FastDHT transfer protocol
* @param header package header
* @param bs byte buff
*/
public static void packHeader(PkgHeader header, byte[] bs) throws UnsupportedEncodingException
{
Arrays.fill(bs, 0, FDHT_PROTO_PKG_HEADER_SIZE, (byte)0);
ProtoCommon.int2buff(header.body_len, bs,PROTO_HEADER_BODY_LEN_INDEX);
ProtoCommon.int2buff(header.key_hash_code, bs, PROTO_HEADER_KEY_HASH_CODE_INDEX);
ProtoCommon.int2buff(header.timestamp, bs, PROTO_HEADER_TIMESTAMP_INDEX);
ProtoCommon.int2buff(header.expires, bs, PROTO_HEADER_EXPIRES_INDEX);
bs[PROTO_HEADER_CMD_INDEX] = header.cmd;
bs[PROTO_HEADER_KEEP_ALIVE_INDEX] = header.keep_alive;
bs[PROTO_HEADER_STATUS_INDEX] = header.status;
return;
}
/**
* receive pack header
* @param in input stream
* @param expect_cmd expect response command
* @param expect_body_len expect response package body length
* @return PkgHeader: status and pkg body length
*/
public static PkgHeader recvHeader(InputStream in, byte expect_cmd, long expect_body_len) throws IOException
{
PkgHeader header;
byte[] bs;
int bytes;
header = new PkgHeader();
bs = new byte[FDHT_PROTO_PKG_HEADER_SIZE];
if ((bytes=in.read(bs)) != bs.length)
{
throw new IOException("recv package size " + bytes + " != " + bs.length);
}
header.cmd = bs[PROTO_HEADER_CMD_INDEX];
if (header.cmd != expect_cmd)
{
throw new IOException("recv cmd: " + bs[PROTO_HEADER_CMD_INDEX] + " is not correct, expect cmd: " + expect_cmd);
}
header.status = bs[PROTO_HEADER_STATUS_INDEX];
header.body_len = ProtoCommon.buff2int(bs, PROTO_HEADER_BODY_LEN_INDEX);
if (header.body_len < 0)
{
throw new IOException("recv body length: " + header.body_len + " < 0!");
}
if (header.status == 0)
{
if (expect_body_len >= 0 && header.body_len != expect_body_len)
{
throw new IOException("recv body length: " + header.body_len + " is not correct, expect length: " + expect_body_len);
}
header.timestamp = ProtoCommon.buff2int(bs, PROTO_HEADER_TIMESTAMP_INDEX);
header.expires = ProtoCommon.buff2int(bs, PROTO_HEADER_EXPIRES_INDEX);
}
return header;
}
/**
* receive whole pack
* @param in input stream
* @param expect_cmd expect response command
* @param expect_body_len expect response package body length
* @return PkgInfo: status and reponse body(byte buff)
*/
public static PkgInfo recvPackage(InputStream in, byte expect_cmd, long expect_body_len) throws IOException
{
PkgHeader header = recvHeader(in, expect_cmd, expect_body_len);
if (header.status != 0)
{
return new PkgInfo(header, null);
}
byte[] body = new byte[header.body_len];
int totalBytes = 0;
int remainBytes = header.body_len;
int bytes;
while (totalBytes < header.body_len)
{
if ((bytes=in.read(body, totalBytes, remainBytes)) < 0)
{
break;
}
totalBytes += bytes;
remainBytes -= bytes;
}
if (totalBytes != header.body_len)
{
throw new IOException("recv package size " + totalBytes + " != " + header.body_len);
}
return new PkgInfo(header, body);
}
/**
* send quit command to server and close socket
* @param sock the Socket object
*/
public static void quit(Socket sock) throws IOException
{
PkgHeader header;
byte[] bs = new byte[FDHT_PROTO_PKG_HEADER_SIZE];
header = new PkgHeader();
header.cmd = FDHT_PROTO_CMD_QUIT;
packHeader(header, bs);
sock.getOutputStream().write(bs);
sock.close();
}
/**
* int convert to buff (big-endian)
* @param n number
* @return 4 bytes buff
*/
public static byte[] int2buff(int n)
{
byte[] bs;
bs = new byte[4];
bs[0] = (byte)((n >> 24) & 0xFF);
bs[1] = (byte)((n >> 16) & 0xFF);
bs[2] = (byte)((n >> 8) & 0xFF);
bs[3] = (byte)(n & 0xFF);
return bs;
}
/**
* int convert to buff (big-endian)
* @param n number
* @param bs byte buff
* @param offset buff start index
*/
public static void int2buff(int n, byte[] bs, int offset)
{
bs[offset] = (byte)((n >> 24) & 0xFF);
bs[offset+1] = (byte)((n >> 16) & 0xFF);
bs[offset+2] = (byte)((n >> 8) & 0xFF);
bs[offset+3] = (byte)(n & 0xFF);
return;
}
/**
* big-endian buff convert to int
* @param bs 4 bytes buff
* @param offset start index
* @return int number
*/
public static int buff2int(byte[] bs, int offset)
{
return (((int)(bs[offset] >= 0 ? bs[offset] : 256+bs[offset])) << 24) |
(((int)(bs[offset+1] >= 0 ? bs[offset+1] : 256+bs[offset+1])) << 16) |
(((int)(bs[offset+2] >= 0 ? bs[offset+2] : 256+bs[offset+2])) << 8) |
((int)(bs[offset+3] >= 0 ? bs[offset+3] : 256+bs[offset+3]));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy