void listen_from_peers() { struct peer_state* peer = peers; unsigned int msglen = 0; while(missing_blocks() > 0) { fd_set fdrset_clone; fd_set fdwset_clone; FD_COPY(&fdrset,&fdrset_clone); FD_COPY(&fdwset,&fdwset_clone); int rdy = select(FD_SETSIZE,&fdrset_clone,&fdwset_clone,0, 0); if(rdy <= 0) { continue; } peer = peers; if(active_peers() == 0){ break; } while(peer){ if(FD_ISSET(peer->socket,&fdwset_clone)){ if(peer->connected == 0){ //to send the handshake if it is not connected send_handshake(peer); } else if(peer->send_count > 0) { //to send the have/interested/piece messages to peers send_buffed_msg(peer); } } if(FD_ISSET(peer->socket,&fdrset_clone)) { int newbytes = recv(peer->socket,peer->incoming+peer->count,BUFSIZE-peer->count,0); if(newbytes <= 0){ peer->trying_to_connect = 0; if(newbytes == 0){ piece_status[peer->requested_piece] = PIECE_EMPTY; } disconnet_peer(peer); reconnect_peer(peer); peer = peer->next; continue; } peer->count += newbytes; if(!peer->handshaked){ peer->count -= peer->incoming[0]+49; if(peer->count) { memmove(peer->incoming,peer->incoming + peer->incoming[0]+49,peer->count); } peer->handshaked = 1; } if(memcmp(peer->incoming+peer->incoming[0]+8+20,"-UICCS450-",strlen("-UICCS450-"))==0) { fprintf(stderr,"Caught a CS450 peer, exiting.\n"); disconnet_peer(peer); continue; } while(peer->count >= (ntohl(((int*)peer->incoming)[0])) + 4){ msglen = ntohl(((int*)peer->incoming)[0]); switch(peer->incoming[4]) { // CHOKE case 0: { if(debug) fprintf(stderr,"Choke\n"); peer->choked = 1; piece_status[peer->requested_piece]=PIECE_EMPTY; peer->requested_piece = -1; break; } // UNCHOKE case 1: { if(debug) fprintf(stderr,"Unchoke\n"); peer->choked = 0; peer->requested_piece = next_piece(-1,peer); request_block(peer,peer->requested_piece,0); break; } //Interested case 2: { //dev_notifier(); send_choke_unchoke_msg(peer,0); //ischoked = 0 peer->not_interested = 0; break; } //Not interested case 3: { //dev_notifier(); peer->not_interested = 1; break; } // HAVE -- update the bitfield for this peer case 4: { int piece = ntohl(*((int*)&peer->incoming[5])); int bitfield_byte = piece/8; int bitfield_bit = piece%8; if(debug) fprintf(stderr,"Have %d\n",piece); peer->bitfield[bitfield_byte] |= 1 << (7 - bitfield_bit); piece_occurence_value[piece]++; send_interested(peer); break; } // BITFIELD -- set the bitfield for this peer case 5: //peer->choked = 0; //commenting it according to prof's note in class if(debug) printf("Bitfield of length %d\n",msglen-1); int fieldlen = msglen - 1; if(fieldlen != (file_length/piece_length/8+1)) { disconnet_peer(peer); if(active_peers() == 0){ break; } peer = peer->next; continue; } memcpy(peer->bitfield,peer->incoming+5,fieldlen); read_bit_maps(peer->bitfield,fieldlen); send_interested(peer); break; //Request piece case 6: { if(peer->i_choked_it == 1) break; decode_request_send_piece_to_peer(peer); } break; // PIECE case 7: { //make the tit for tatter peer->send_recv_balancer++; if(peer->i_choked_it && peer->send_recv_balancer == 0){ peer->i_choked_it = 0; send_choke_unchoke_msg(peer,0); //unchoke peer } int piece = ntohl(*((int*)&peer->incoming[5])); int offset = ntohl(*((int*)&peer->incoming[9])); int datalen = msglen - 9; fprintf(stderr,"Writing piece %d, offset %d, ending at %d\n",piece,offset,piece*piece_length+offset+datalen); write_block(peer->incoming+13,piece,offset,datalen,1); draw_state(); offset+=datalen; if(offset==piece_length || (piece*piece_length+offset == file_length) ) { broadcast_have_msg(piece); draw_state(); if(debug) fprintf(stderr,"Reached end of piece %d at offset %d\n",piece,offset); peer->requested_piece=next_piece(piece,peer); offset = 0; } request_block(peer,peer->requested_piece,offset); break; } } drop_message(peer); } } peer = peer->next; } } return; }
int Peer::clock() { if (m_state == PEER_STATE_SEND_HANDSHAKE) { if (m_sock == NULL) { try { m_nm->Socket_add(m_addr, shared_from_this(), m_sock); } catch (...) { goto_sleep(); return ERR_INTERNAL; } } if (send_handshake() != ERR_NO_ERROR) goto_sleep(); if (send_bitfield() != ERR_NO_ERROR) goto_sleep(); m_state = PEER_STATE_WAIT_HANDSHAKE; } if (!m_peer_choking) { if (m_state == PEER_STATE_GENERAL_READY ) m_state = PEER_STATE_REQUEST_READY; } else if (m_state == PEER_STATE_GENERAL_READY || m_state == PEER_STATE_REQUEST_READY) { send_interested(); m_state = PEER_STATE_WAIT_UNCHOKE; } //если находимся в нужном состоянии и очередь не пуста if ((m_state == PEER_STATE_GENERAL_READY || m_state == PEER_STATE_REQUEST_READY || m_state == PEER_STATE_WAIT_UNCHOKE) && !m_requests_queue.empty()) { char block[BLOCK_LENGTH]; uint32_t block_length; PIECE_INDEX piece_index; BLOCK_INDEX block_index; std::set<BLOCK_ID>::iterator iter = m_requests_queue.begin(); get_piece_block_from_block_id(*iter, piece_index, block_index); //если удалось прочитать блок и отправить, удаляем индекс блока из очереди if (m_torrent->read_block(piece_index, block_index, block, block_length) == ERR_NO_ERROR && send_piece(piece_index, BLOCK_LENGTH * block_index, block_length, block) == ERR_NO_ERROR) { m_requests_queue.erase(iter); m_torrent->inc_uploaded(block_length); m_uploaded += block_length; //logger::LOGGER() << "rx=%f tx=%f\n", get_rx_speed(), get_tx_speed()); } } if (m_state == PEER_STATE_REQUEST_READY && m_requested_blocks.size() <= PEER_MAX_REQUEST_NUMBER && !m_blocks2request.empty()) { std::set<BLOCK_ID>::iterator iter = m_blocks2request.begin(); PIECE_INDEX piece; BLOCK_INDEX block; uint32_t length; get_piece_block_from_block_id(*iter, piece, block); m_torrent->get_block_length_by_index(piece, block, length); if (send_request(piece, block, length) == ERR_NO_ERROR) { m_requested_blocks.insert(*iter); m_blocks2request.erase(iter); } } return ERR_NO_ERROR; }
// handles the message. no, we *don't* need to pass in msglen int handle_message(struct peer_state* peer) { int msglen = ntohl(((int*)peer->incoming)[0]); // because not returned from receive message int newbytes = 0; fflush(stdout); if(msglen == 0) { piece_status[peer->requested_piece] = PIECE_EMPTY; draw_state(); shutdown_peer(peer); return 0; } // not picking any of the cases in switch; calling handle_message prematurely? switch(peer->incoming[4]) { // CHOKE case 0: { if(debug) fprintf(stderr,"Choke\n"); peer->choked = 1; piece_status[peer->requested_piece] = PIECE_EMPTY; peer->requested_piece = -1; break; } // UNCHOKE case 1: { if(debug) fprintf(stderr,"Unchoke\n"); peer->choked = 0; // grab a new piece - WARNING: this assumes that you don't get choked mid-piece! peer->requested_piece = next_piece(-1); // keep track of how many bytes downloaded of the piece // add to piece_status request_block(peer,peer->requested_piece,0); break; } // INTERESTED case 2: { // TODO: Send unchoke message to peer (?) peer->choked = 0; // unchoke peer break; } // HAVE -- update the bitfield for this peer case 4: { int piece_index = ntohl(*((int*)&peer->incoming[5])); int bitfield_byte = piece_index/8; int bitfield_bit = 7-(piece_index%8); if(debug) fprintf(stderr,"Have %d\n", piece_index); peer->bitfield[bitfield_byte] |= 1 << bitfield_bit; send_interested(peer); break; } // BITFIELD - set the bitfield for this peer case 5: { peer->choked = 0; if(debug) printf("Bitfield of length %d\n", msglen-1); int fieldlen = msglen - 1; if(fieldlen != (file_length/piece_length/8+1)) { fprintf(stderr,"Incorrect bitfield size, expected %d\n", file_length/piece_length/8+1); shutdown_peer(peer); return 0; } memcpy(peer->bitfield,peer->incoming+5,fieldlen); send_interested(peer); break; } // REQUEST case 6: { // peer is requesting piece // copy from file // send to them // update ratio information break; } // PIECE case 7: { int piece = ntohl(*((int*)&peer->incoming[5])); int offset = ntohl(*((int*)&peer->incoming[9])); int datalen = msglen - 9; fprintf(stderr,"Writing piece %d, offset %d, ending at %d\n", piece, offset, piece*piece_length+offset+datalen); write_block(peer->incoming+13,piece,offset,datalen,1); // save this block to comp draw_state(); // segfault source? offset += datalen; if(offset==piece_length || (piece*piece_length+offset == file_length) ) { if(debug) fprintf(stderr, "Reached end of piece %d at offset %d\n", piece, offset); peer->requested_piece = next_piece(piece); offset = 0; if(peer->requested_piece == -1) { fprintf(stderr,"No more pieces to download!\n"); // but don't exit if sth. is still being downloaded for(int i = 0; i < file_length/piece_length+1; i++) if(piece_status[i] != 2) { shutdown_peer(peer); return 0; } shutdown_peer(peer); return 0; } } request_block(peer,peer->requested_piece,offset); break; } case 20: { printf("Extended type is %d\n", peer->incoming[5]); struct bencode *extended = ben_decode(peer->incoming,msglen); print_bencode(extended); break; } } drop_message(peer); return 1; }