BitTorrent协议分析六

论坛 期权论坛 脚本     
匿名网站用户   2020-12-21 08:15   11   0

ul int process_handshake_msg(Peer *peer,unsigned char *buff,int len)

功能:处理接收到的一条握手消息。

参数:从peer接收到这条握手消息;buff指向握手消息;lenbuff的长度。函数实现的代码如下:

int process_handshake_msg(Peer *peer,unsigned char *buff,int len)

{

if(peer==NULL || buff==NULL) return -1;

if(memcmp(info_hash,buff+28,20) != 0) { // info_hash不一致则关闭连接

peer->state = CLOSING;

// 丢弃发送缓冲区中的数据

discard_send_buffer(peer);

clear_btcache_before_peer_close(peer);

close(peer->socket);

return -1;

}

// 保存该peerpeer_id

memcpy(peer->id,buff+48,20);

(peer->id)[20] = '\0';

// 若当前处于Initial状态,则发送握手消息给peer

if(peer->state == INITIAL) {

create_handshake_msg(info_hash,peer_id,peer);

peer->state = HANDSHAKED;

}

// 若握手消息已发送,则状态转换为已握手状态

if(peer->state == HALFSHAKED) peer->state = HANDSHAKED;

// 记录最近收到该peer消息的时间

// 若一定时间内(如两分钟)未收到来自该peer的任何消息,则关闭连接

peer->start_timestamp = time(NULL);

return 0;

}

ul int process_keep_alive_msg(Peer *peer,unsigned char *buff,int len)

功能:处理刚刚接收到的来自peerkeepv_alive消息。函数实现的代码如下:

int process_keep_alive_msg(Peer *peer,unsigned char *buff,int len)

{

if(peer==NULL || buff==NULL) return -1;

// 记录最近收到该peer消息的时间

// 若一定时间内(2min)未收到来自该peer的任何消息,则关闭连接

peer->start_timestamp = time(NULL);

return 0;

}

ul int process_choke_msg(Peer *peer,unsigned char *buff,int len)

功能:处理收到的choke消息。函数实现的代码如下:

int process_choke_msg(Peer *peer,unsigned char *buff,int len)

{

if(peer==NULL || buff==NULL) return -1;

// 若原先处于unchoke状态,收到该消息后更新peer中某些变量的值

if( peer->state!=CLOSING && peer->peer_choking==0 ) {

peer->peer_choking = 1;

peer->last_down_timestamp = 0; // 将最近接收到来自该peer数据的时间清零

peer->down_count = 0; // 将最近从该peer处下载的字节数清零

peer->down_rate = 0; // 将最近从该peer下载数据的速度清零

}

peer->start_timestamp = time(NULL);

return 0;

}

ul int process_unchoke_msg(Peer *peer,unsigned char *buff,int len)

功能:处理收到unchoke消息。函数实现的代码如下:

int process_unchoke_msg(Peer *peer,unsigned char *buff,int len)

{

if(peer==NULL || buff==NULL) return -1;

// 若原来处于choke状态且与该peer的连接未被关闭

if( peer->state!=CLOSING && peer->peer_choking==1 ) {

peer->peer_choking = 0;

// 若对该peer感兴趣,则构造request消息请求peer发送数据

if(peer->am_interested == 1) create_req_slice_msg(peer);

else {

peer->am_interested = is_interested(&(peer->bitmap), bitmap);

if(peer->am_interested == 1) create_req_slice_msg(peer);

else printf("Received unchoke but Not interested to IP:%s \n",peer->ip);

}

// 更新一些成员的值

peer->last_down_timestamp = 0;

peer->down_count = 0;

peer->down_rate = 0;

}

peer->start_timestamp = time(NULL);

return 0;

}

ul int process_interested_msg(Peer *peer,unsigned char *buff,int len)

功能:处理收到的interested消息。函数实现的代码如下:

int process_interested_msg(Peer *peer,unsigned char *buff,int len)

{

if(peer==NULL || buff==NULL) return -1;

if( peer->state!=CLOSING && peer->state==DATA ) {

peer->peer_interested = is_interested(bitmap, &(peer->bitmap));

if(peer->peer_interested == 0) return -1;

if(peer->am_choking == 0) create_chock_interested_msg(1,peer);

}

peer->start_timestamp = time(NULL);

return 0;

}

ul int process_uninterested_msg(Peer *peer,unsigned char *buff,int len)

功能:处理收到的uninterested消息。函数实现的代码如下:

int process_uninterested_msg(Peer *peer,unsigned char *buff,int len)

{

if(peer==NULL || buff==NULL) return -1;

if( peer->state!=CLOSING && peer->state==DATA ) {

peer->peer_interested = 0;

cancel_requested_list(peer);

}

peer->start_timestamp = time(NULL);

return 0;

}

ul int process_have_msg(Peer *peer,unsigned char *buff,int len)

功能:处理收到的have消息。函数实现的代码如下:

int process_have_msg(Peer *peer,unsigned char *buff,int len)

{

int rand_num;

unsigned char c[4];

if(peer==NULL || buff==NULL) return -1;

srand(time(NULL));

rand_num = rand() % 3; // 生成一个02的随机数

if( peer->state!=CLOSING && peer->state==DATA ) {

c[0] = buff[5]; c[1] = buff[6];

c[2] = buff[7]; c[3] = buff[8];

// 更新该peer的位图

if(peer->bitmap.bitfield != NULL)

set_bit_value(&(peer->bitmap),char_to_int(c),1);

if(peer->am_interested == 0) {

peer->am_interested = is_interested(&(peer->bitmap), bitmap);

// 由原来的对peer不感兴趣变为感兴趣时,发送interested消息

if(peer->am_interested == 1) create_chock_interested_msg(2,peer);

} else { // 收到3have则发一个interested消息

if(rand_num == 0) create_chock_interested_msg(2,peer);

}

}

peer->start_timestamp = time(NULL);

return 0;

}

ul int process_cancel_msg(Peer *peer,unsigned char *buff,int len)

功能:处理收到的cancel消息。函数实现的代码如下:

int process_cancel_msg(Peer *peer,unsigned char *buff,int len)

{

unsigned char c[4];

int index, begin, length;

if(peer==NULL || buff==NULL) return -1;

c[0] = buff[5]; c[1] = buff[6];

c[2] = buff[7]; c[3] = buff[8];

index = char_to_int(c);

c[0] = buff[9]; c[1] = buff[10];

c[2] = buff[11]; c[3] = buff[12];

begin = char_to_int(c);

c[0] = buff[13]; c[1] = buff[14];

c[2] = buff[15]; c[3] = buff[16];

length = char_to_int(c);

// 在被请求队列中删除指定的请求

Request_piece *p, *q;

p = q = peer->Requested_piece_head;

while(p != NULL) {

if( p->index==index && p->begin==begin && p->length==length ) {

if(p == peer->Requested_piece_head)

peer->Requested_piece_head = p->next;

else

q->next = p->next;

free(p);

break;

}

q = p;

p = p->next;

}

peer->start_timestamp = time(NULL);

return 0;

}

ul int process_bitfield_msg(Peer *peer,unsigned char *buff,int len)

功能:处理收到的位图消息。函数实现的代码如下:

int process_bitfield_msg(Peer *peer,unsigned char *buff,int len)

{

unsigned char c[4];

if(peer==NULL || buff==NULL) return -1;

if(peer->state==HANDSHAKED || peer->state==SENDBITFIELD) {

c[0] = buff[0]; c[1] = buff[1];

c[2] = buff[2]; c[3] = buff[3];

// 若原先已收到一个位图消息,则清空原来的位图

if( peer->bitmap.bitfield != NULL ) {

free(peer->bitmap.bitfield);

peer->bitmap.bitfield = NULL;

}

peer->bitmap.valid_length = bitmap->valid_length;

if(bitmap->bitfield_length != char_to_int(c)-1) { // 若收到的一个错误位图

peer->state = CLOSING;

// 丢弃发送缓冲区中的数据

discard_send_buffer(peer);

clear_btcache_before_peer_close(peer);

close(peer->socket);

return -1;

}

// 生成该peer的位图

peer->bitmap.bitfield_length = char_to_int(c) - 1;

peer->bitmap.bitfield = (unsigned char*)malloc(peer->bitmap.bitfield_length);

memcpy(peer->bitmap.bitfield,&buff[5],peer->bitmap.bitfield_length);

// 如果原状态为已握手,收到位图后应该向peer发位图

if(peer->state == HANDSHAKED) {

create_bitfield_msg(bitmap->bitfield,bitmap->bitfield_length,peer);

peer->state = DATA;

}

// 如果原状态为已发送位图,收到位图后可以进入DATA状态准备交换数据

if(peer->state == SENDBITFIELD) {

peer->state = DATA;

}

// 根据位图判断peer是否对本客户端感兴趣

peer->peer_interested = is_interested(bitmap,&(peer->bitmap));

// 判断对peer是否感兴趣,若是则发送interested消息

peer->am_interested = is_interested(&(peer->bitmap), bitmap);

if(peer->am_interested == 1) create_chock_interested_msg(2,peer);

}

peer->start_timestamp = time(NULL);

return 0;

}

ul int process_request_msg(Peer *peer,unsigned char *buff,int len)

功能:处理收到的request消息。函数实现代码如下:

int process_request_msg(Peer *peer,unsigned char *buff,int len)

{

unsigned char c[4];

int index, begin, length;

Request_piece *request_piece, *p;

if(peer==NULL || buff==NULL) return -1;

if(peer->am_choking==0 && peer->peer_interested==1) {

c[0] = buff[5]; c[1] = buff[6];

c[2] = buff[7]; c[3] = buff[8];

index = char_to_int(c);

c[0] = buff[9]; c[1] = buff[10];

c[2] = buff[11]; c[3] = buff[12];

begin = char_to_int(c);

c[0] = buff[13]; c[1] = buff[14];

c[2] = buff[15]; c[3] = buff[16];

length = char_to_int(c);

// 查看该请求是否已存在,若已存在,则不进行处理

p = peer->Requested_piece_head;

while(p != NULL) {

if(p->index==index && p->begin==begin && p->length==length) {

break;

}

p = p->next;

}

if(p != NULL) return 0;

// 将请求加入到请求队列中

request_piece = (Request_piece *)malloc(sizeof(Request_piece));

if(request_piece == NULL) {

printf("%s:%d error",__FILE__,__LINE__);

return 0;

}

request_piece->index = index;

request_piece->begin = begin;

request_piece->length = length;

request_piece->next = NULL;

if( peer->Requested_piece_head == NULL )

peer->Requested_piece_head = request_piece;

else {

p = peer->Requested_piece_head;

while(p->next != NULL) p = p->next;

p->next = request_piece;

}

// 打印提示信息

printf("***add a request FROM IP:%s index:%-6d begin:%-6x ***\n",

peer->ip,index,begin);

}

peer->start_timestamp = time(NULL);

return 0;

}

ul int process_piece_msg(Peer *peer,unsigned char *buff,int len)

功能:处理收到的piece消息。函数实现代码如下:

int process_piece_msg(Peer *peer,unsigned char *buff,int len)

{

unsigned char c[4];

int index, begin, length;

Request_piece *p;

if(peer==NULL || buff==NULL) return -1;

if(peer->peer_choking==0) {

c[0] = buff[0]; c[1] = buff[1];

c[2] = buff[2]; c[3] = buff[3];

length = char_to_int(c) - 9;

c[0] = buff[5]; c[1] = buff[6];

c[2] = buff[7]; c[3] = buff[8];

index = char_to_int(c);

c[0] = buff[9]; c[1] = buff[10];

c[2] = buff[11]; c[3] = buff[12];

begin = char_to_int(c);

// 判断收到的slice是否是请求过的

p = peer->Request_piece_head;

while(p != NULL) {

if(p->index==index && p->begin==begin && p->length==length)

break;

p = p->next;

}

if(p == NULL) {printf("did not found matched request\n"); return -1;}

// 开始记时,并累计收到数据的字节数

if(peer->last_down_timestamp == 0)

peer->last_down_timestamp = time(NULL);

peer->down_count += length;

peer->down_total += length;

// 将收到的数据写入缓冲区中

write_slice_to_btcache(index,begin,length,buff+13,length,peer);

// 生成请求数据的消息,要求继续发送数据

create_req_slice_msg(peer);

}

peer->start_timestamp = time(NULL);

return 0;

}

ul int parse_response(Peer *peer)

功能:处理收到的消息(peer的接收缓冲区中可能存放着多条消息)。函数实现代码如下:

int parse_response(Peer *peer)

{

unsigned char btkeyword[20];

unsigned char keep_alive[4] = { 0x0, 0x0, 0x0, 0x0 };

int index;

unsigned char *buff = peer->in_buff; // in_buff为接收缓冲区

int len = peer->buff_len; // buff_len为接收缓冲区中有效数据的长度

if(buff==NULL || peer==NULL) return -1;

btkeyword[0] = 19;

memcpy(&btkeyword[1],"BitTorrent protocol",19); // BitTorrent协议关键字

// 分别处理12种消息

for(index = 0; index < len; ) {

if( (len-index >= 68) && (memcmp(&buff[index],btkeyword,20) == 0) ) {

process_handshake_msg(peer,buff+index,68);

index += 68;

}

else if( (len-index >= 4) && (memcmp(&buff[index],keep_alive,4) == 0)) {

process_keep_alive_msg(peer,buff+index,4);

index += 4;

}

else if( (len-index >= 5) && (buff[index+4] == CHOKE) ) {

process_choke_msg(peer,buff+index,5);

index += 5;

}

else if( (len-index >= 5) && (buff[index+4] == UNCHOKE) ) {

process_unchoke_msg(peer,buff+index,5);

index += 5;

}

else if( (len-index >= 5) && (buff[index+4] == INTERESTED) ) {

process_interested_msg(peer,buff+index,5);

index += 5;

}

else if( (len-index >= 5) && (buff[index+4] == UNINTERESTED) ) {

process_uninterested_msg(peer,buff+index,5);

index += 5;

}

else if( (len-index >= 9) && (buff[index+4] == HAVE) ) {

process_have_msg(peer,buff+index,9);

index += 9;

}

else if( (len-index >= 5) && (buff[index+4] == BITFIELD) ) {

process_bitfield_msg(peer,buff+index,peer->bitmap.bitfield_length+5);

index += peer->bitmap.bitfield_length + 5;

}

else if( (len-index >= 17) && (buff[index+4] == REQUEST) ) {

process_request_msg(peer,buff+index,17);

index += 17;

}

else if( (len-index >= 13) && (buff[index+4] == PIECE) ) {

unsigned char c[4];

int length;

c[0] = buff[index]; c[1] = buff[index+1];

c[2] = buff[index+2]; c[3] = buff[index+3];

length = char_to_int(c) - 9;

process_piece_msg(peer,buff+index,length+13);

index += length + 13; // length+13piece消息的长度

}

else if( (len-index >= 17) && (buff[index+4] == CANCEL) ) {

process_cancel_msg(peer,buff+index,17);

index += 17;

}

else if( (len-index >= 7) && (buff[index+4] == PORT) ) {

index += 7;

}

else {

// 如果是未知的消息类型,则跳过不予处理

unsigned char c[4];

int length;

if(index+4 <= len) {

c[0] = buff[index]; c[1] = buff[index+1];

c[2] = buff[index+2]; c[3] = buff[index+3];

length = char_to_int(c);

if(index+4+length <= len) { index += 4+length; continue; }

}

// 如果是一条错误的消息,清空接收缓冲区

peer->buff_len = 0;

return -1;

}

} // for语句结束

// 接收缓冲区中的消息处理完毕后,清空接收缓冲区

peer->buff_len = 0;

return 0;

}

ul int parse_response_uncomplete_msg(Peer *p,int ok_len)

功能:处理收到的消息。

参数:ok_len为接收缓冲区中完整消息的长度。函数实现代码如下:

int parse_response_uncomplete_msg(Peer *p,int ok_len)

{

char *tmp_buff;

int tmp_buff_len;

// 分配存储空间,并保存接收缓冲区中不完整的消息

tmp_buff_len = p->buff_len - ok_len;

if(tmp_buff_len <= 0) return -1;

tmp_buff = (char *)malloc(tmp_buff_len);

if(tmp_buff == NULL) {

printf("%s:%d error\n",__FILE__,__LINE__);

return -1;

}

memcpy(tmp_buff,p->in_buff+ok_len,tmp_buff_len);

// 处理接收缓冲区中前面完整的消息

p->buff_len = ok_len;

parse_response(p);

// 将不完整的消息拷贝到接收缓冲区的开始处

memcpy(p->in_buff,tmp_buff,tmp_buff_len);

p->buff_len = tmp_buff_len;

if(tmp_buff != NULL) free(tmp_buff);

return 0;

}

ul int prepare_send_have_msg()

说明:当下载完一个piece,应该向所有的peer发送have消息。函数实现的代码如下:

int prepare_send_have_msg()

{

Peer *p = peer_head;

int i;

if(peer_head == NULL) return -1;

if(have_piece_index[0] == -1) return -1;

while(p != NULL) {

for(i = 0; i < 64; i++) {

if(have_piece_index[i] != -1) create_have_msg(have_piece_index[i],p);

else break;

}

p = p->next;

}

for(i = 0; i < 64; i++) {

if(have_piece_index[i] == -1) break;

else have_piece_index[i] = -1;

}

return 0;

}

ul int create_response_message(Peer *peer)

功能:主动创建发送给peer的消息,而不是等收到某个消息后再创建响应消息。函数实现的代码如下:

int create_response_message(Peer *peer)

{

if(peer==NULL) return -1;

if(peer->state == INITIAL) { // 处于Intial状态时主动发握手消息

create_handshake_msg(info_hash,peer_id,peer);

peer->state = HALFSHAKED;

return 0;

}

if(peer->state == HANDSHAKED) { // 处于已握手状态,主动发位图消息

if(bitmap == NULL) return -1;

create_bitfield_msg(bitmap->bitfield,bitmap->bitfield_length,peer);

peer->state = SENDBITFIELD;

return 0;

}

// 如果条件允许(未将该peer阻塞,且peer发送过请求),则主动发送piece消息

if( peer->am_choking==0 && peer->Requested_piece_head!=NULL ) {

Request_piece *req_p = peer->Requested_piece_head;

int ret = read_slice_for_send(req_p->index,req_p->begin,req_p->length,peer);

if(ret < 0 ) { printf("read_slice_for_send ERROR\n");}

else {

if(peer->last_up_timestamp == 0)

peer->last_up_timestamp = time(NULL);

peer->up_count += req_p->length;

peer->up_total += req_p->length;

peer->Requested_piece_head = req_p->next;

// 打印提示信息

// printf("*** sending a slice TO:%s index:%-5d begin:%-5x ***\n",

// peer->ip,req_p->index,req_p->begin);

free(req_p);

return 0;

}

}

// 如果3分钟没有收到任何消息关闭连接

time_t now = time(NULL); // 获取当前时间

long interval1 = now - peer->start_timestamp;

if( interval1 > 180 ) {

peer->state = CLOSING;

// 丢弃发送缓冲区中的数据

discard_send_buffer(peer);

// 将从该peer处下载到的不足一个piece的数据删除

clear_btcache_before_peer_close(peer);

close(peer->socket);

}

// 如果45秒没有发送和接收到消息,则发送一个keep_alive消息

long interval2 = now - peer->recet_timestamp;

if( interval1>45 && interval2>45 && peer->msg_len==0)

create_keep_alive_msg(peer);

return 0;

}

ul void discard_send_buffer(Peer *peer)

功能:即将与peer断开时,丢弃发送缓冲区中的消息。函数实现的代码如下:

void discard_send_buffer(Peer *peer)

{

struct linger lin;

int lin_len;

lin.l_onoff = 1;

lin.l_linger = 0;

lin_len = sizeof(lin);

// 通过设置套接字选项来丢弃未发送的数据

if(peer->socket > 0) {

setsockopt(peer->socket,SOL_SOCKET,SO_LINGER,(char *)&lin,lin_len);

}

}

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:1136255
帖子:227251
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP