void handle_message(cjdnsadmin_t *adm, char *buffer, ssize_t len) { // TODO: fix memory leak struct bencode *b = ben_decode(buffer, len); if (!b) { fprintf(stderr, "bencode error: %lu\n",len); printf("message from cjdns: \"%*s\"\n", (int)len, buffer); return; } // Get IPs struct bencode *table = ben_dict_get_by_str(b, "routingTable"); size_t i, num_items = ben_list_len(table); for (i = 0; i < num_items; i++) { struct bencode *item = ben_list_get(table, i); struct bencode *ip = ben_dict_get_by_str(item, "ip"); if (ben_is_str(ip)) { const char *ip_str = ben_str_val(ip); if (adm->on_found_ip) { (*adm->on_found_ip)(adm->on_found_ip_obj, ip_str); } } } // check if there is more struct bencode *more = ben_dict_get_by_str(b, "more"); int more_int = more && ben_is_int(more) && ben_int_val(more); if (more_int == 1) { // get the next page of the routing table adm->fetch_peers_page++; cjdnsadmin_fetch_peers(adm); } else { // start from the first page next time adm->fetch_peers_page = 0; } ben_free(b); }
/* handle_announcement reads an announcement document to find some peers to download from. Puts em in benPeers, and we then handle the peer scanning or whatever in the main function. */ void handle_announcement(char *ptr, size_t size) { struct bencode* anno = ben_decode(ptr,size); printf("Torrent has %lld seeds and %lld downloading peers. \n", ((struct bencode_int*)ben_dict_get_by_str(anno,"complete"))->ll, ((struct bencode_int*)ben_dict_get_by_str(anno,"incomplete"))->ll); benPeers = (struct bencode_list*)ben_dict_get_by_str(anno,"peers"); }
/* handle_announcement reads an announcement document to find some peers to download from. start a new tread for each peer. */ void handle_announcement(char *ptr, size_t size) { struct bencode* anno = ben_decode(ptr,size); printf("Torrent has %lld seeds and %lld downloading peers. \n", ((struct bencode_int*)ben_dict_get_by_str(anno,"complete"))->ll, ((struct bencode_int*)ben_dict_get_by_str(anno,"incomplete"))->ll); struct bencode_list *peers = (struct bencode_list*)ben_dict_get_by_str(anno,"peers"); // handle the binary case if(peers->type == BENCODE_STR) { printf("Got binary list of peers\n"); struct peer_addr *peerlist = (struct peer_addr*)((struct bencode_str*)peers)->s; for(int i=0;i<((struct bencode_str*)peers)->len/6;i++) { struct in_addr a; a.s_addr = peerlist[i].addr; printf("Found peer %s:%d\n",inet_ntoa(a),ntohs(peerlist[i].port)); connect_all_peers(&peerlist[i]); } } // handle the bencoded case else { for(int i=0;i<peers->n;i++) { printf("Got bencoded list of peers\n"); struct bencode *peer = peers->values[i]; char *address = ((struct bencode_str*)ben_dict_get_by_str(peer,"ip"))->s; unsigned short port = ((struct bencode_int*)ben_dict_get_by_str(peer,"port"))->ll; printf("Found peer %s:%d\n",address,port); struct peer_addr *peeraddr = malloc(sizeof(struct peer_addr)); peeraddr->addr=inet_addr(address); peeraddr->port=htons(port); connect_all_peers(peeraddr); } } listen_from_peers(); }
// 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; }