peer.c文件的头部包含的代码如下:
peer.c
#include
#include
#include
#include "peer.h"
#include "message.h"
#include "bitfield.h"
extern Bitmap *bitmap;
// 指向当前与之进行通信的peer链表
Peer *peer_head = NULL;
peer.c中各个函数的定义如下。
ul initialize_peer(Peer *peer)
int initialize_peer(Peer *peer)
{
if(peer == NULL) return -1;
peer->socket = -1;
memset(peer->ip,0,16);
peer->port = 0;
memset(peer->id,0,21);
peer->state = INITIAL;
peer->in_buff = NULL;
peer->out_msg = NULL;
peer->out_msg_copy = NULL;
peer->in_buff = (char *)malloc(MSG_SIZE);
if(peer->in_buff == NULL) goto OUT;
memset(peer->in_buff,0,MSG_SIZE);
peer->buff_len = 0;
peer->out_msg = (char *)malloc(MSG_SIZE);
if(peer->out_msg == NULL) goto OUT;
memset(peer->out_msg,0,MSG_SIZE);
peer->msg_len = 0;
peer->out_msg_copy = (char *)malloc(MSG_SIZE);
if(peer->out_msg_copy == NULL) goto OUT;
memset(peer->out_msg_copy,0,MSG_SIZE);
peer->msg_copy_len = 0;
peer->msg_copy_index = 0;
peer->am_choking = 1;
peer->am_interested = 0;
peer->peer_choking = 1;
peer->peer_interested = 0;
peer->bitmap.bitfield = NULL;
peer->bitmap.bitfield_length = 0;
peer->bitmap.valid_length = 0;
peer->Request_piece_head = NULL;
peer->Requested_piece_head = NULL;
peer->down_total = 0;
peer->up_total = 0;
peer->start_timestamp = 0;
peer->recet_timestamp = 0;
peer->last_down_timestamp = 0;
peer->last_up_timestamp = 0;
peer->down_count = 0;
peer->up_count = 0;
peer->down_rate = 0.0;
peer->up_rate = 0.0;
peer->next = (Peer *)0;
return 0;
OUT:
if(peer->in_buff != NULL) free(peer->in_buff);
if(peer->out_msg != NULL) free(peer->out_msg);
if(peer->out_msg_copy != NULL) free(peer->out_msg_copy);
return -1;
}
ul Peer* add_peer_node()
Peer* add_peer_node()
{
int ret;
Peer *node, *p;
// 分配内存空间
node = (Peer *)malloc(sizeof(Peer));
if(node == NULL) {
printf("%s:%d error\n",__FILE__,__LINE__);
return NULL;
}
// 进行初始化
ret = initialize_peer(node);
if(ret < 0) {
printf("%s:%d error\n",__FILE__,__LINE__);
free(node);
return NULL;
}
// 将node加入到peer链表中
if(peer_head == NULL) { peer_head = node; } // node为peer链表的第一个结点
else {
p = peer_head; // 使p指针指向peer链表的最后一个结点
while(p->next != NULL) p = p->next;
p->next = node;
}
return node;
}
ul int del_peer_node(Peer *peer)
int del_peer_node(Peer *peer)
{
Peer *p = peer_head, *q;
if(peer == NULL) return -1;
while(p != NULL) {
if( p == peer ) {
if(p == peer_head) peer_head = p->next;
else q->next = p->next;
free_peer_node(p);
return 0;
} else {
q = p;
p = p->next;
}
}
return -1;
}
ul int cancel_request_list(Peer *node)
// 撤销当前请求队列
int cancel_request_list(Peer *node)
{
Request_piece *p = node->Request_piece_head;
while(p != NULL) {
node->Request_piece_head = node->Request_piece_head->next;
free(p);
p = node->Request_piece_head;
}
return 0;
}
ul int cancel_requested_list(Peer *node)
// 撤销当前被请求队列
int cancel_requested_list(Peer *node)
{
Request_piece * p = node->Requested_piece_head;
while(p != NULL) {
node->Requested_piece_head = node->Requested_piece_head->next;
free(p);
p = node->Requested_piece_head;
}
return 0;
}
ul void free_peer_node(Peer *node)
void free_peer_node(Peer *node)
{
if(node == NULL) return;
if(node->bitmap.bitfield != NULL) free(node->bitmap.bitfield);
if(node->in_buff != NULL) free(node->in_buff);
if(node->out_msg != NULL) free(node->out_msg);
if(node->out_msg_copy != NULL) free(node->out_msg_copy);
// 撤销请求队列和被请求队列
cancel_request_list(node);
cancel_requested_list(node);
// 释放完peer成员的内存后,再释放peer所占的内存
free(node);
}
ul void release_memory_in_peer()
void release_memory_in_peer()
{
Peer *p;
if(peer_head == NULL) return;
p = peer_head;
while(p != NULL) {
peer_head = peer_head->next;
free_peer_node(p);
p = peer_head;
}
}
ul void print_peers_data()
void print_peers_data()
{
Peer *p = peer_head;
int index = 0;
while(p != NULL) {
printf("peer: %d IP %s down_rate: %.2f \n", index, p->ip, p->down_rate);
index++;
p = p->next;
}
}
消息处理模块负责根据当前的状态生成并发送消息,接收以及处理消息。消息处理模块由messag.h和message.c两个文件构成,理解和分析本模块的代码时请参考图13-3、图13-4和图13-5。
message.h
#ifndef MESSAGE_H
#define MESSAGE_H
#include "peer.h"
int int_to_char(int i, unsigned char c[4]); // 将整型变量i的4个字节存放到数组c中
int char_to_int(unsigned char c[4]); // 将数组c中的4个字节转换为一个整型数
// 以下函数创建各个类型的消息,创建消息的函数请参考BT协议加以理解
int create_handshake_msg(char *info_hash,char *peer_id,Peer *peer);
int create_keep_alive_msg(Peer *peer);
int create_chock_interested_msg(int type,Peer *peer);
int create_have_msg(int index,Peer *peer);
int create_bitfield_msg(char *bitfield,int bitfield_len,Peer *peer);
int create_request_msg(int index,int begin,int length,Peer *peer);
int create_piece_msg(int index,int begin,char *block,int b_len,Peer *peer);
int create_cancel_msg(int index,int begin,int length,Peer *peer);
int create_port_msg(int port,Peer *peer);
// 判断接收缓冲区中是否存放了一条完整的消息
int is_complete_message(unsigned char *buff,unsigned int len,int *ok_len);
// 处理收到的消息,接收缓冲区中存放着一条完整的消息
int parse_response(Peer *peer);
// 处理收到的消息,接收缓冲区中除了存放着一条完整的消息外,还有其他不完整的消息
int parse_response_uncomplete_msg(Peer *p,int ok_len);
// 根据当前的状态创建响应消息
int create_response_message(Peer *peer);
// 为发送have消息作准备,have消息较为特殊,它要发送给所有peer
int prepare_send_have_msg();
// 即将与peer断开时,丢弃套接字发送缓冲区中的所有未发送的消息
void discard_send_buffer(Peer *peer);
#endif
message.c文件的头部包括的代码如下:
message.h
#include
#include
#include
#include
#include
#include
#include
#include
#include "parse_metafile.h"
#include "bitfield.h"
#include "peer.h"
#include "policy.h"
#include "data.h"
#include "message.h"
#define HANDSHAKE -2 // 握手消息
#define KEEP_ALIVE -1 // keep_alive消息
#define CHOKE 0 // choke消息
#define UNCHOKE 1 // unchoke消息
#define INTERESTED 2 // interested消息
#define UNINTERESTED 3 // uninterested消息
#define HAVE 4 // have消息
#define BITFIELD 5 // bitfield消息
#define REQUEST 6 // request消息
#define PIECE 7 // piece消息
#define CANCEL 8 // cancel消息
#define PORT 9 // port消息
// 如果45秒未给某peer发送消息,则发送keep_alive消息
#define KEEP_ALIVE_TIME 45
extern Bitmap *bitmap; // 在bitmap.c中定义,指向己方的位图
extern char info_hash[20]; // 在parse_metafile.c中定义,存放info_hash
extern char peer_id[20]; // 在parse_metafile.c中定义,存放peer_id
extern int have_piece_index[64]; // 在data.c中定义,存放下载到的piece的index
extern Peer *peer_head; // 在peer.c中定义,指向peer链表
message.c中各个函数的定义如下:
ul int int_to_char(int i, unsigned char c[4])
int int_to_char(int i, unsigned char c[4])
{
c[3] = i%6;
c[2] = (i-c[3])/256%6;
c[1] = (i-c[3]-c[2]*256)/256/256%6;
c[0] = (i-c[3]-c[2]*256-c[1]*256*256)/256/256/256%6;
return 0;
}
程序说明。
假设i = 123456789,若以16进制表示该数为0x75BCD15,则c[0] = 07,c[1] = 5B,c[2] = CD,c[3] = 15。函数char_to_int的功能与本函数刚好相反。
ul int char_to_int(unsigned char c[4])
int char_to_int(unsigned char c[4])
{
int i;
i = c[0]*256*256*256 + c[1]*256*256 + c[2]*256 + c[3];
return i;
}
ul int create_handshake_msg(char *info_hash,char *peer_id,Peer *peer)
参数:info_hash在parse_metafile.c中由种子文件计算而得;peer_id也在parse_metafile.c中生成;peer为要发送握手消息给某一个peer的指针变量。
返回:创建消息成功返回0,创建失败返回-1。函数实现代码如下:
int create_handshake_msg(char *info_hash,char *peer_id,Peer *peer)
{
int i;
unsigned char keyword[20] = "BitTorrent protocol", c = 0x00;
unsigned char *buffer = peer->out_msg + peer->msg_len;
int len = MSG_SIZE - peer->msg_len;
if(len < 68) return -1; // 握手消息的长度固定为68字节
buffer[0] = 19;
for(i = 0; i < 19; i++) buffer[i+1] = keyword[i];
for(i = 0; i < 8; i++) buffer[i+20] = c;
for(i = 0; i < 20; i++) buffer[i+28] = info_hash[i];
for(i = 0; i < 20; i++) buffer[i+48] = peer_id[i];
peer->msg_len += 68;
return 0;
}
程序说明。
将生成的握手消息存放在peer结点的发送缓冲区中(即msg_out),其中msg_out[0]~msg_out[msg_len-1]已存放了其他消息。函数中变量len指明缓冲区还有多少空闲。初始情况下,msg_len的值应为0。
ul int create_keep_alive_msg(Peer *peer)
int create_keep_alive_msg(Peer *peer)
{
unsigned char *buffer = peer->out_msg + peer->msg_len;
int len = MSG_SIZE - peer->msg_len;
if(len < 4) return -1; // keep_alive消息的长度固定为4
memset(buffer,0,4);
peer->msg_len += 4;
return 0;
}
ul int create_chock_interested_msg(int type,Peer *peer)
int create_chock_interested_msg(int type,Peer *peer)
{
unsigned char *buffer = peer->out_msg + peer->msg_len;
int len = MSG_SIZE - peer->msg_len;
// choke、unchoke、interested、uninterested消息的长度固定为5
if(len < 5) return -1;
memset(buffer,0,5);
buffer[3] = 1;
buffer[4] = type;
peer->msg_len += 5;
return 0;
}
程序说明。
该函数可创建4种消息,即choke、unchoke、interested、uninterested消息。choke消息的type值为0,unchoke消息为1,interested消息为2,uninterested消息为3。
ul int create_have_msg(int index,Peer *peer)
int create_have_msg(int index,Peer *peer)
{
unsigned char *buffer = peer->out_msg + peer->msg_len;
int len = MSG_SIZE - peer->msg_len;
unsigned char c[4];
if(len < 9) return -1; // have消息的长度固定为9
memset(buffer,0,9);
buffer[3] = 5;
buffer[4] = 4;
int_to_char(index,c); // index为piece的下标
buffer[5] = c[0];
buffer[6] = c[1];
buffer[7] = c[2];
buffer[8] = c[3];
peer->msg_len += 9;
return 0;
}
ul int create_bitfield_msg(char *bitfield,int bitfield_len,Peer *peer)
int create_bitfield_msg(char *bitfield,int bitfield_len,Peer *peer)
{
int i;
unsigned char c[4];
unsigned char *buffer = peer->out_msg + peer->msg_len;
int len = MSG_SIZE - peer->msg_len;
if( len < bitfield_len+5 ) { // bitfield消息的长度为bitfield_len+5
printf("%s:%d buffer too small\n",__FILE__,__LINE__);
return -1;
}
int_to_char(bitfield_len+1,c); // 位图消息的负载长度为位图长度加1
for(i = 0; i < 4; i++) buffer[i] = c[i];
buffer[4] = 5;
for(i = 0; i < bitfield_len; i++) buffer[i+5] = bitfield[i];
peer->msg_len += bitfield_len+5;
return 0;
}
ul int create_request_msg(int index,int begin,int length,Peer *peer)
功能:创建数据请求消息。
参数:index为请求的piece的下标;begin为piece内的偏移量;length为请求数据的长度。函数实现的代码如下:
int create_request_msg(int index,int begin,int length,Peer *peer)
{
int i;
unsigned char c[4];
unsigned char *buffer = peer->out_msg + peer->msg_len;
int len = MSG_SIZE - peer->msg_len;
if(len < 17) return -1; // request消息的长度固定为17
memset(buffer,0,17);
buffer[3] = 13;
buffer[4] = 6;
int_to_char(index,c);
for(i = 0; i < 4; i++) buffer[i+5] = c[i];
int_to_char(begin,c);
for(i = 0; i < 4; i++) buffer[i+9] = c[i];
int_to_char(length,c);
for(i = 0; i < 4; i++) buffer[i+13] = c[i];
peer->msg_len += 17;
return 0;
}
ul int create_piece_msg(int index,int begin,char *block,int b_len,Peer *peer)
功能:创建piece消息。
参数:block指向待发送的数据;b_len为block所指向的数据的长度。函数实现的代码如下:
int create_piece_msg(int index,int begin,char *block,int b_len,Peer *peer)
{
int i;
unsigned char c[4];
unsigned char *buffer = peer->out_msg + peer->msg_len;
int len = MSG_SIZE - peer->msg_len;
if( len < b_len+13 ) { // piece消息的长度为b_len+13
printf("%s:%d buffer too small\n",__FILE__,__LINE__);
return -1;
}
int_to_char(b_len+9,c);
for(i = 0; i < 4; i++) buffer[i] = c[i];
buffer[4] = 7;
int_to_char(index,c);
for(i = 0; i < 4; i++) buffer[i+5] = c[i];
int_to_char(begin,c);
for(i = 0; i < 4; i++) buffer[i+9] = c[i];
for(i = 0; i < b_len; i++) buffer[i+13] = block[i];
peer->msg_len += b_len+13;
return 0;
}
ul int create_cancel_msg(int index,int begin,int length,Peer *peer)
int create_cancel_msg(int index,int begin,int length,Peer *peer)
{
int i;
unsigned char c[4];
unsigned char *buffer = peer->out_msg + peer->msg_len;
int len = MSG_SIZE - peer->msg_len;
if(len < 17) return -1; // cancel消息的长度固定为17
memset(buffer,0,17);
buffer[3] = 13;
buffer[4] = 8;
int_to_char(index,c);
for(i = 0; i < 4; i++) buffer[i+5] = c[i];
int_to_char(begin,c);
for(i = 0; i < 4; i++) buffer[i+9] = c[i];
int_to_char(length,c);
for(i = 0; i < 4; i++) buffer[i+13] = c[i];
peer->msg_len += 17;
return 0;
}
ul int create_port_msg(int port,Peer *peer)
附注:实际上程序从未发送过本消息,因为根据BT协议,该消息是为那些以DHT的方式获取peer地址的应用程序所准备的。函数实现的代码如下:
int create_port_msg(int port,Peer *peer)
{
unsigned char c[4];
unsigned char *buffer = peer->out_msg + peer->msg_len;
int len = MSG_SIZE - peer->msg_len;
if( len < 7) return 0; // port消息的长度固定为7
memset(buffer,0,7);
buffer[3] = 3;
buffer[4] = 9;
int_to_char(port,c);
buffer[5] = c[2];
buffer[6] = c[3];
peer->msg_len += 7;
return 0;
}
ul int is_complete_message(unsigned char *buff,unsigned int len,int *ok_len)
功能:判断缓冲区中是否存放了一条完整的消息。
参数:buff指向存放消息的缓冲区;len为缓冲区buff的长度;ok_len用于返回缓冲区中完整消息的长度,即buff[0]~buff[ok_len-1]存放着一条或多条完整的消息。函数实现的完整代码如下:
int is_complete_message(unsigned char *buff,unsigned int len,int *ok_len)
{
unsigned int i;
char btkeyword[20];
unsigned char keep_alive[4] = { 0x0, 0x0, 0x0, 0x0 };
unsigned char chocke[5] = { 0x0, 0x0, 0x0, 0x1, 0x0};
unsigned char unchocke[5] = { 0x0, 0x0, 0x0, 0x1, 0x1};
unsigned char interested[5] = { 0x0, 0x0, 0x0, 0x1, 0x2};
unsigned char uninterested[5] = { 0x0, 0x0, 0x0, 0x1, 0x3};
unsigned char have[5] = { 0x0, 0x0, 0x0, 0x5, 0x4};
unsigned char request[5] = { 0x0, 0x0, 0x0, 0xd, 0x6};
unsigned char cancel[5] = { 0x0, 0x0, 0x0, 0xd, 0x8};
unsigned char port[5] = { 0x0, 0x0, 0x0, 0x3, 0x9};
if(buff==NULL || len<=0 || ok_len==NULL) return -1;
*ok_len = 0;
btkeyword[0] = 19;
memcpy(&btkeyword[1],"BitTorrent protocol",19); // BitTorrent协议关键字
unsigned char c[4];
unsigned int length;
for(i = 0; i < len; ) {
// 握手、chocke、have等消息的长度是固定的
if( i+68<=len && memcmp(&buff[i],btkeyword,20)==0 ) i += 68;
else if( i+4 <=len && memcmp(&buff[i],keep_alive,4)==0 ) i += 4;
else if( i+5 <=len && memcmp(&buff[i],chocke,5)==0 ) i += 5;
else if( i+5 <=len && memcmp(&buff[i],unchocke,5)==0 ) i += 5;
else if( i+5 <=len && memcmp(&buff[i],interested,5)==0 ) i += 5;
else if( i+5 <=len && memcmp(&buff[i],uninterested,5)==0 ) i += 5;
else if( i+9 <=len && memcmp(&buff[i],have,5)==0 ) i += 9;
else if( i+17<=len && memcmp(&buff[i],request,5)==0 ) i += 17;
else if( i+17<=len && memcmp(&buff[i],cancel,5)==0 ) i += 17;
else if( i+7 <=len && memcmp(&buff[i],port,5)==0 ) i += 7;
else if( i+5 <=len && buff[i+4]==5 ) { // bitfield消息的长度是变化的
c[0] = buff[i]; c[1] = buff[i+1];
c[2] = buff[i+2]; c[3] = buff[i+3];
length = char_to_int(c);
// 消息长度占4字节,消息本身占length个字节
if( i+4+length <= len ) i += 4+length;
else { *ok_len = i; return -1; }
}
else if( i+5 <=len && buff[i+4]==7 ) { // piece消息的长度也是变化的
c[0] = buff[i]; c[1] = buff[i+1];
c[2] = buff[i+2]; c[3] = buff[i+3];
length = char_to_int(c);
// 消息长度占4字节,消息本身占length个字节
if( i+4+length <= len ) i += 4+length;
else { *ok_len = i; return -1; }
}
else {
// 处理未知类型的消息
if(i+4 <= len) {
c[0] = buff[i]; c[1] = buff[i+1];
c[2] = buff[i+2]; c[3] = buff[i+3];
length = char_to_int(c);
// 消息长度占4字节,消息本身占length个字节
if(i+4+length <= len) { i += 4+length; continue; }
else { *ok_len = i; return -1; }
}
// 如果不是未知消息类型,则认为目前接收的数据还不是一个完整的消息
*ok_len = i;
return -1;
}
} // for语句结束
*ok_len = i;
return 1;
}