📄 fileagentpacket.java
字号:
* @param in
* @throws PacketParseException
*/
private void parseForward(ByteBuffer in) throws PacketParseException {
// 会话ID
sessionId = (char)in.getInt();
// 未知的4字节
in.getInt();
// 被转发的包长度
in.getChar();
// 被转发的包
fdp.parse(in);
}
/**
* 从in的当前位置开始解析请求中转回复包包体
* @param in ByteBuffer对象
* @throws PacketParseException
*/
private void parseRequestAgent(ByteBuffer in) throws PacketParseException {
// 应答码
replyCode = in.getChar();
if(replyCode == QQ.QQ_FILE_AGENT_SERVICE_APPROVED) {
// 得到中转服务器ip和端口
agentIp = new byte[4];
agentIp[3] = in.get();
agentIp[2] = in.get();
agentIp[1] = in.get();
agentIp[0] = in.get();
agentPort = in.getChar();
// 文件会话id
sessionId = (char)in.getInt();
} else if(replyCode == QQ.QQ_FILE_AGENT_SERVICE_REDIRECTED) {
in.position(in.position() + 10);
// 得到重定向服务器ip和端口
agentIp = new byte[4];
agentIp[3] = in.get();
agentIp[2] = in.get();
agentIp[1] = in.get();
agentIp[0] = in.get();
agentPort = in.getChar();
} else
throw new PacketParseException("请求中转回复包的应答类型不支持");
}
/**
* 从in的当前位置开始解析头部
* @param in
* @throws PacketParseException
*/
private void parseHead(ByteBuffer in) throws PacketParseException {
// 检查包头标志
if(in.get() != QQ.QQ_HEADER_04_FAMILY)
throw new PacketParseException("错误的中转包头");
// 跳过source
in.getChar();
// 得到包长,检查包长是否正确(通过检查最后一个字节是不是0x3)
int len = in.getChar();
if(in.get(in.position() + len - 4) != QQ.QQ_TAIL_BASIC_FAMILY)
throw new PacketParseException("中转包长度有误");
// 命令
command = in.getChar();
// 序号
sequence = in.getChar();
// 检查QQ号字段
if(in.getInt() != watcher.getMyQQ())
throw new PacketParseException("不是给我的包,抛弃");
// 未知的8字节
in.getLong();
}
/**
* 从out的当前未知填充包尾
* @param out
*/
private void putTail(ByteBuffer out) {
out.put(QQ.QQ_TAIL_BASIC_FAMILY);
}
/**
* 从out的当前未知开始填充包体
* @param out ByteBuffer对象
*/
private void putBody(ByteBuffer out) {
switch(command) {
case QQ.QQ_FILE_CMD_REQUEST_AGENT:
/* 0x0001 */
initRequestAgent(out);
break;
case QQ.QQ_FILE_CMD_CHECK_IN:
/* 0x0002 */
initCheckIn(out);
break;
case QQ.QQ_FILE_CMD_FORWARD:
/* 0x0003 */
initForward(out);
break;
case QQ.QQ_FILE_CMD_FORWARD_FINISHED:
/* 0x0004 */
initForwardFinished(out);
break;
case QQ.QQ_FILE_CMD_IT_IS_TIME:
/* 0x0005 */
initItIsTime(out);
break;
case QQ.QQ_FILE_CMD_I_AM_READY:
/* 0x0006 */
initIAmReady(out);
break;
default:
log.error("不支持的命令类型");
break;
}
}
/**
* 从out当前位置开始填充报到包
* @param out ByteBuffer对象
*/
private void initCheckIn(ByteBuffer out) {
out.putInt(watcher.getSessionSequence());
buffer.clear();
buffer.putChar((char)watcher.getFileAgentToken().length);
buffer.put(watcher.getFileAgentToken());
byte[] backArray = buffer.array();
out.put(crypter.encrypt(backArray, 0, buffer.position(), watcher.getFileAgentKey()));
}
/**
* 从out当前位置开始填充我准备好了的请求包
* @param out ByteBuffer对象
*/
private void initIAmReady(ByteBuffer out) {
out.putInt(watcher.getSessionSequence());
buffer.clear();
buffer.putChar((char)0);
byte[] backArray = buffer.array();
out.put(crypter.encrypt(backArray, 0, buffer.position(), watcher.getFileAgentKey()));
}
/**
* 从out当前位置开始填充准备传输回复包
* @param out ByteBuffer对象
*/
private void initItIsTime(ByteBuffer out) {
out.putInt(watcher.getSessionSequence());
buffer.clear();
buffer.putInt(0);
byte[] backArray = buffer.array();
out.put(crypter.encrypt(backArray, 0, buffer.position(), watcher.getFileAgentKey()));
}
/**
* 从out当前位置开始填充中转结束包的其余部分
* @param out ByteBuffer对象
*/
private void initForwardFinished(ByteBuffer out) {
out.putInt(watcher.getSessionSequence());
buffer.clear();
buffer.putInt(watcher.getMyQQ())
.putChar((char)0);
byte[] backArray = buffer.array();
out.put(crypter.encrypt(backArray, 0, buffer.position(), watcher.getFileAgentKey()));
}
/**
* 从out当前位置开始填充中转包的其余部分
* @param out ByteBuffer对象
*/
private void initForward(ByteBuffer out) {
// TODO 未知的4字节先用0
out.putInt(watcher.getSessionSequence())
.putInt(0)
.putChar((char)0); // 数据包长度,暂时设为0
// 保存当前位置
int pos = out.position();
// 写入数据包
fdp.fill(out, pos);
// 修改数据包长度字段
out.putChar(pos - 2, (char)(out.position() - pos));
}
/**
* 从out当前位置开始填充请求中转包的其余部分
* @param out ByteBuffer对象
*/
private void initRequestAgent(ByteBuffer out) {
out.putChar((char)watcher.getFileAgentToken().length)
.put(watcher.getFileAgentToken());
buffer.clear();
buffer.putChar((char)0x07D0)
.putInt(watcher.getHisQQ());
byte[] backArray = buffer.array();
out.put(crypter.encrypt(backArray, 0, buffer.position(), watcher.getFileAgentKey()));
}
/**
* 从out的当前未知开始填充包头
* @param out ByteBuffer对象
*/
private void putHead(ByteBuffer out) {
// TODO 暂时未知的8字节用0
out.put(QQ.QQ_HEADER_04_FAMILY)
.putChar(QQ.QQ_CLIENT_VERSION)
.putChar((char)0)
.putChar(command)
.putChar(sequence)
.putInt(watcher.getMyQQ())
.putLong(0);
}
/**
* @return Returns the command.
*/
public char getCommand() {
return command;
}
/**
* @param command The command to set.
*/
public void setCommand(char command) {
this.command = command;
}
/**
* @return Returns the sequence.
*/
public char getSequence() {
return sequence;
}
/**
* @param sequence The sequence to set.
*/
public void setSequence(char sequence) {
this.sequence = sequence;
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object obj) {
if(obj instanceof FileAgentPacket)
return ((FileAgentPacket)obj).hashCode() == hashCode();
else
return false;
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
public int hashCode() {
return (sequence << 16) | command;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -