BitTorrent协议分析六

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);

     }

}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值