Esempio n. 1
0
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);
}
Esempio n. 2
0
/* 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");
}
Esempio n. 3
0
/* 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();
}
Esempio n. 4
0
void write_block(char* data, int piece, int offset, int len, int acquire_lock) {
    FILE *outfile;

    //dev_notifier(); 
    int accumulated_file_length = 0;
    int block_start = piece*piece_length+offset;

    struct bencode_list* files = (struct bencode_list*)ben_dict_get_by_str(info,"files");
    // multi-file case
    if(files) {
        for(int i=0;i<files->n;i++) {
            struct bencode* file = files->values[i];
            struct bencode_list* path = (struct bencode_list*)ben_dict_get_by_str(file,"path");
            int file_length=((struct bencode_int*)ben_dict_get_by_str(file,"length"))->ll; 

            printf("start %d len %d accum %d filelen %d\n",block_start,len,accumulated_file_length,file_length);

            // at least part of the block belongs in this file
            if((block_start >= accumulated_file_length) && (block_start < accumulated_file_length+file_length)) {
                char filename[255];
                
                mkdir(((struct bencode_str*)ben_dict_get_by_str(info,"name"))->s,0777);
                chmod(((struct bencode_str*)ben_dict_get_by_str(info,"name"))->s,07777);
                
                sprintf(filename,"%s/",((struct bencode_str*)ben_dict_get_by_str(info,"name"))->s);
                for(int j=0;j<path->n;j++) {                    
                    if(j<(path->n-1)) {
                        sprintf(filename+strlen(filename),"%s/",((struct bencode_str*)path->values[j])->s);
                        mkdir(filename,0777);
                        chmod(filename,07777);
                    }
                    else
                        sprintf(filename+strlen(filename),"%s",((struct bencode_str*)path->values[j])->s);
                }   
                
                int outfile = open(filename,O_RDWR|O_CREAT,0777);
                if(outfile == -1) {
                    fprintf(stderr,"filename: %s\n",filename);
                    perror("Couldn't open file for writing");
                    exit(1);
                }
                
                int offset_into_file = block_start - accumulated_file_length;
                int remaining_file_length = file_length - offset_into_file;
                lseek(outfile,offset_into_file,SEEK_SET);

                if(remaining_file_length > len) {
                    write(outfile,data,len);
                    close(outfile);
                    goto cleanup;
                }
                else {
                    write(outfile,data,remaining_file_length);
                    close(outfile);
                    write_block(data+remaining_file_length,piece,offset+remaining_file_length,len-remaining_file_length,0);
                    goto cleanup;
                }

            }
            accumulated_file_length+=file_length;
        }
    }
    // single-file case
    else {

        struct bencode_str* name = (struct bencode_str*)ben_dict_get_by_str(info,"name");
        if(name) {
            FILE *outfile = fopen(name->s,"r+");
            file_length = ((struct bencode_int*)ben_dict_get_by_str(info,"length"))->ll;            

            // write the data to the right spot in the file
            fseek(outfile,piece*piece_length+offset,SEEK_SET);
            fwrite(data,1,len,outfile);
            fclose(outfile);
    
        }
        else {
            printf("No name?\n");
            exit(1);
        }
    }
    
 cleanup:
    return;
}
Esempio n. 5
0
int main(int argc, char** argv) {

    //setvbuf(stdout,screenbuf,_IOFBF,10000);
    setbuf(stdout, NULL);
    setbuf(stderr, NULL);
        
    // create a global peer_id for this session. Every peer_id should include -CS450-.
    for(int i=strlen(peer_id);i<20;i++)
        peer_id[i]='0'+random()%('Z'-'0'); // random numbers/letters between 0 and Z
    
    // make sure the torrent file exists
    struct stat file_stat;
    if(stat(argv[1],&file_stat)) {
        perror("Error opening file.");
        exit(1);
    }

    // map .torrent file into memory, and parse contents
    int fd = open(argv[1],O_RDONLY);
    char *buf = mmap(0,file_stat.st_size,PROT_READ,MAP_SHARED,fd,0);
    if(buf==(void*)-1) {
        perror("couldn't mmap file");
        exit(1);
    }        
    size_t off = 0;
    int error = 0;
    torrent = (struct bencode_dict*)ben_decode2(buf,file_stat.st_size,&off,&error);
    if(!torrent) {
        printf("Got error %d, perhaps a malformed torrent file?\n",error);
        exit(1);
    }

    // pull out the .info part, which has stuff about the file we're downloading
    info = (struct bencode*)ben_dict_get_by_str((struct bencode*)torrent,"info");
    
    struct bencode_list* files = (struct bencode_list*)ben_dict_get_by_str(info,"files");
    // multi-file case
    if(files) {
        for(int i=0;i<files->n;i++) {
            struct bencode* file = files->values[i];
            struct bencode_list* path = (struct bencode_list*)ben_dict_get_by_str(file,"path");
            printf("Filename %s/%s\n",((struct bencode_str*)ben_dict_get_by_str(info,"name"))->s,((struct bencode_str*)path->values[0])->s);

            // accumulate a total length so we know how many pieces there are 
            file_length+=((struct bencode_int*)ben_dict_get_by_str(file,"length"))->ll; 
        }
    }
    // single-file case
    else {
        FILE *outfile;
        struct bencode_str* name = (struct bencode_str*)ben_dict_get_by_str(info,"name");
        if(name) {
            outfile = fopen(name->s,"r+");
            file_length = ((struct bencode_int*)ben_dict_get_by_str(info,"length"))->ll;            
        }
    }

    piece_length = ((struct bencode_int*)ben_dict_get_by_str(info,"piece length"))->ll;

    piece_status  =calloc(1,sizeof(int)*(int)(file_length/piece_length+1));
    /* compute the message digest and info_hash from the "info" field in the torrent */
    size_t len;
    char info_hash[100];  
    char* encoded = ben_encode(&len,(struct bencode*)info);
    SHA1(encoded,len,digest); // digest is a global that holds the raw 20 bytes
    piece_occurence_value = calloc(1,sizeof(int)*(int)(file_length/piece_length+1));
  
    // info_hash is a stringified version of the digest, for use in the announce URL
    memset(info_hash,0,100);
    for(int i=0;i<20;i++)
        sprintf(info_hash+3*i,"%%%02x",digest[i]);

    // compile a suitable announce URL for our document
    sprintf(announce_url,"%s?info_hash=%s&peer_id=%s&port=6881&left=%d",((struct bencode_str*)ben_dict_get_by_str((struct bencode*)torrent,"announce"))->s,info_hash,peer_id,file_length);
    printf("Announce URL: %s\n",announce_url);

    start_peers();
}
Esempio n. 6
0
int main(int argc, char** argv) {
	if(argc<2) {
		fprintf(stderr,"Usage: ./hw4 <torrent file>\n");
		exit(1);
	}

	setvbuf(stdout,screenbuf,_IOFBF,10000);
		
	// create a global peer_id for this session. Every peer_id should include -OBCS342-.
	for(int i=strlen(peer_id);i<20;i++)
		peer_id[i]='0'+random()%('Z'-'0'); // random numbers/letters between 0 and Z
	
	// make sure the torrent file exists
	struct stat file_stat;
	if(stat(argv[1],&file_stat)) {
		perror("Error opening file.");
		exit(1);
	}

	// map .torrent file into memory, and parse contents
	int fd = open(argv[1],O_RDONLY);
	char *buf = mmap(0,file_stat.st_size,PROT_READ,MAP_SHARED,fd,0);
	if(buf==(void*)-1) {
		perror("couldn't mmap file");
		exit(1);
	}		 
	size_t off = 0;
	int error = 0;
	torrent = (struct bencode_dict*)ben_decode2(buf,file_stat.st_size,&off,&error);
	if(!torrent) {
		printf("Got error %d, perhaps a malformed torrent file?\n",error);
		exit(1);
	}

	// pull out the .info part, which has stuff about the file we're downloading
	info = (struct bencode*)ben_dict_get_by_str((struct bencode*)torrent,"info");
	
	struct bencode_list* files = (struct bencode_list*)ben_dict_get_by_str(info,"files");
	// multi-file case
	if(files) {
		for(int i=0;i<files->n;i++) {
			struct bencode* file = files->values[i];
			struct bencode_list* path = (struct bencode_list*)ben_dict_get_by_str(file,"path");
			printf("Filename %s/%s\n",((struct bencode_str*)ben_dict_get_by_str(info,"name"))->s,((struct bencode_str*)path->values[0])->s);

			// accumulate a total length so we know how many pieces there are 
			file_length+=((struct bencode_int*)ben_dict_get_by_str(file,"length"))->ll; 
		}
	}
	// single-file case
	else {
		struct bencode_str* name = (struct bencode_str*)ben_dict_get_by_str(info,"name");
		if(name) {
			file_length = ((struct bencode_int*)ben_dict_get_by_str(info,"length"))->ll;			
		}
	}
	fflush(stdout);
	piece_length = ((struct bencode_int*)ben_dict_get_by_str(info,"piece length"))->ll;

	// create our output file, and set up a piece_status array
	piece_status = calloc(1,sizeof(int)*(int)(file_length/piece_length+1)); //start with an empty bitfield

	/* compute the message digest and info_hash from the "info" field in the torrent */
	size_t len;
	char info_hash[100];  
	char* encoded = ben_encode(&len,(struct bencode*)info);
	SHA1(encoded,len,digest); // digest is a global that holds the raw 20 bytes
	
	// info_hash is a stringified version of the digest, for use in the announce URL
	memset(info_hash,0,100);
	for(int i=0;i<20;i++)
		sprintf(info_hash+3*i,"%%%02x",digest[i]);

	// compile a suitable announce URL for our document
	sprintf(announce_url,"%s?info_hash=%s&peer_id=%s&port=6881&left=%d",((struct bencode_str*)ben_dict_get_by_str((struct bencode*)torrent,"announce"))->s,info_hash,peer_id,file_length);
	printf("Announce URL: %s\n",announce_url);
	fflush(stdout);

	start_peers(); 

	// now benPeers has the peers list from handle_announcement; let's handle this
	// handle the binary case
	FD_ZERO(&readset);
	FD_ZERO(&writeset); // zero out the sets before adding things to them
	if(benPeers->type == BENCODE_STR) {
		printf("Got binary list of peers\n");
		// replace all occurrences of pa with peerlist[i]
		struct peer_addr *peerlist = (struct peer_addr*)((struct bencode_str*)benPeers)->s;
		for(int i=0;i<((struct bencode_str*)benPeers)->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));	
			
			fprintf(stderr,"Connecting...\n");
			struct peer_addr* peeraddr = (struct peer_addr*)&peerlist[i];

	 		if(peer_connected(peeraddr->addr)) {
		 		fprintf(stderr,"Already connected\n");
	    	} else {
	    	 	// open the socket
	    	 	int s = socket(AF_INET, SOCK_STREAM,0);
	    	 	if(s < 0){
	    	 		perror("Error creating socket: ");
	    	 	}
	    	 	struct sockaddr_in addr;
	    	 	addr.sin_family = AF_INET;
	    	 	addr.sin_addr.s_addr = peeraddr->addr;
	    	 	addr.sin_port = peeraddr->port;

	    	 	// set up the timeout
	    	 	struct timeval tv;
	    	 	tv.tv_sec = 60;
	    	 	if(setsockopt(s,SOL_SOCKET,SO_RCVTIMEO, (char *)&tv, sizeof tv))
	    	 		perror("setsockopt");
	    	 	int res = connect(s, (struct sockaddr*)&addr, sizeof(addr));
	    	 	if(res == -1) {
	    	 		fprintf(stderr,"Couldn't connect to %d \n", peeraddr->port);
	    	 		fflush(stderr);
	    	 		perror("Error while connecting: ");
	    	 	} else {
	    	 		printf("Connected!\n"); // for debugging purposes
		    	 	// register the new peer in our list of peers
		    	 	struct peer_state* peer = calloc(1,sizeof(struct peer_state));
		    	 	peer->socket = s; // socket is current socket
		    	 	peer->ip= peeraddr->addr; // address is the address of the current peer
		    	 	peer->next = peers; // stick it at the front of the linked list
		    	 	peer->connected = 0; // we're not connected until we've done handshaking
		    	 	peer->choked = 1;
		    	 	peer->incoming = malloc(BUFSIZE);
		    	 	peer->bitfield = calloc(1,file_length/piece_length/8+1); // start with an empty bitfield
		    	 	peers = peer; 	// make me the head of the LL

		    	 	char protocol[] = "BitTorrent protocol";
		    	 	unsigned char pstrlen = strlen(protocol);
		    	 	unsigned char msg[pstrlen+49];
		    	 	msg[0] = pstrlen;
		    	 	memcpy(msg+1,protocol,pstrlen);
		    	 	memcpy(msg+1+pstrlen+8,digest,20);
		    	 	memcpy(msg+1+pstrlen+8+20,peer_id,20);

		    	 	// put handshaking msg into all peers' outgoing
		    	 	peer->outgoing_count = 0;
		    	 	peer->outgoing = malloc(BUFSIZE);
		    	 	memcpy(peer->outgoing+peer->outgoing_count, msg, sizeof msg);
		    	 	peer->outgoing_count += sizeof msg;

		    	 	FD_SET(s, &readset); // add s (fd of peer's socket) to the read and write sets
		    	 	FD_SET(s, &writeset); 
		    	}
	    	 }	
	 	}	 
	}
	// handle the bencoded case
	else {
		for(int i=0;i<benPeers->n;i++) {
			printf("Got bencoded list of peers\n");
			struct bencode *peer = benPeers->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);

			fprintf(stderr,"Connecting...\n");
			struct peer_addr *peeraddr = malloc(sizeof(struct peer_addr));
			peeraddr->addr=inet_addr(address);
			peeraddr->port=htons(port);

	 		if(peer_connected(peeraddr->addr)) {
		 		fprintf(stderr,"Already connected\n");
	    	} else {
	    	 	// open the socket
	    	 	int s = socket(AF_INET, SOCK_STREAM,0);
	    	 	if(s < 0){
	    	 		perror("Error creating socket: ");
	    	 	}
	    	 	struct sockaddr_in addr;
	    	 	addr.sin_family = AF_INET;
	    	 	addr.sin_addr.s_addr = peeraddr->addr;
	    	 	addr.sin_port = peeraddr->port;

	    	 	// set up the timeout
	    	 	struct timeval tv;
	    	 	tv.tv_sec = 60;
	    	 	if(setsockopt(s,SOL_SOCKET,SO_RCVTIMEO, (char *)&tv, sizeof tv))
	    	 		perror("setsockopt");
	    	 	// in a more ideal world, this would break out of the current iteration of the loop
	    	 	int res = connect(s, (struct sockaddr*)&addr, sizeof(addr));
	    	 	if(res == -1) {
	    	 		fprintf(stderr,"Couldn't connect to %d \n", peeraddr->port);
	    	 		fflush(stderr);
	    	 		perror("Error while connecting: ");
	    	 	} else {
	    	 		printf("Connected!\n"); // for debugging purposes
		    	 	// register the new peer in our list of peers
		    	 	struct peer_state* peer = calloc(1,sizeof(struct peer_state));
		    	 	peer->socket = s; // socket is current socket
		    	 	peer->ip= peeraddr->addr; // address is the address of the current peer
    		    	 	peer->next = peers; // stick it at the front of the linked list
		    	 	peer->connected = 0; // we're not connected until we've done handshaking
		    	 	peer->choked = 1;
		    	 	peer->incoming = malloc(BUFSIZE);
		    	 	peer->bitfield = calloc(1,file_length/piece_length/8+1); // start with an empty bitfield
		    	 	peers = peer; 	// make me the head of the LL

		    	 	char protocol[] = "BitTorrent protocol";
		    	 	unsigned char pstrlen = strlen(protocol);
		    	 	unsigned char msg[pstrlen+49];
		    	 	msg[0] = pstrlen;
		    	 	memcpy(msg+1,protocol,pstrlen);
		    	 	memcpy(msg+1+pstrlen+8,digest,20);
		    	 	memcpy(msg+1+pstrlen+8+20,peer_id,20);

		    	 	// put handshaking msg into all peers' outgoing
		    	 	peer->outgoing_count = 0;
		    	 	peer->outgoing = malloc(BUFSIZE);
		    	 	memcpy(peer->outgoing+peer->outgoing_count, msg, sizeof msg);
		    	 	peer->outgoing_count += sizeof msg;

		    	 	FD_SET(s, &readset); // add s (fd of peer's socket) to the read and write sets
		    	 	FD_SET(s, &writeset); 
		    	}
	    	 }	
		}
	}

while(1) {
		fd_set rtemp, wtemp; 
		FD_ZERO(&rtemp);
		FD_ZERO(&wtemp);	// zero out the temp sets
		memcpy(&rtemp, &readset, sizeof readset);
		memcpy(&wtemp, &writeset, sizeof writeset); 

		// timeout for the select call? probably too high
		struct timeval tv;
		tv.tv_sec = 0;

		int selected = select(FD_SETSIZE, &rtemp, &wtemp, NULL, &tv);
		struct peer_state* peerTemp = peers;

		while(peerTemp) {
		  //printf("Current peer name is %s\n", inet_ntoa(*(struct in_addr *)&peerTemp->ip));
			
			if(FD_ISSET(peerTemp->socket,&rtemp)) {		// if we're reading
				if(!peerTemp->connected) {
					recv_handshake(peerTemp);			// can all receive at once? or not?
					FD_SET(peerTemp->socket, &readset);
				} else {
					int ret = receive_message(peerTemp); // we can just use the current receive_message fcn
					if(ret == 2) {
						handle_message(peerTemp);
					} // else just keep on chuggin
				}
				//FD_SET(peerTemp->socket, &readset);		// then add it to the readset, always
			}
			
			if(FD_ISSET(peerTemp->socket,&wtemp)) {		// if we're writing
				send_message(peerTemp);
			}
			peerTemp = peerTemp->next;
		} 
		// if we don't have any missing blocks, breeaaaakk
		if(missing_blocks() == 0) 
			break; 							
}
}
Esempio n. 7
0
/* This needs to be fixed to work properly for multi-file torrents. 
	 specifically, it needs to create the proper directory structure, rather than just concatenate directory and file names. 
 */
void write_block(char* data, int piece, int offset, int len, int acquire_lock) {
	FILE *outfile;

	int accumulated_file_length = 0;
	int block_start = piece*piece_length+offset;

	struct bencode_list* files = (struct bencode_list*)ben_dict_get_by_str(info,"files");
	// multi-file case
	if(files) {
		for(int i=0;i<files->n;i++) {
			struct bencode* file = files->values[i];
			struct bencode_list* path = (struct bencode_list*)ben_dict_get_by_str(file,"path");
			//			printf("Filename %s/%s\n",((struct bencode_str*)ben_dict_get_by_str(info,"name"))->s,((struct bencode_str*)path->values[0])->s);
			// accumulate a total length so we know how many pieces there are 
			int file_length=((struct bencode_int*)ben_dict_get_by_str(file,"length"))->ll; 

			printf("start %d len %d accum %d filelen %d\n",block_start,len,accumulated_file_length,file_length);
			fflush(stdout);
			// at least part of the block belongs in this file
			if((block_start >= accumulated_file_length) && (block_start < accumulated_file_length+file_length)) {
				char filename[255];
				
				mkdir(((struct bencode_str*)ben_dict_get_by_str(info,"name"))->s,0777);
				chmod(((struct bencode_str*)ben_dict_get_by_str(info,"name"))->s,07777);
				
				sprintf(filename,"%s/",((struct bencode_str*)ben_dict_get_by_str(info,"name"))->s);
				for(int j=0;j<path->n;j++) {					
					if(j<(path->n-1)) {
						sprintf(filename+strlen(filename),"%s/",((struct bencode_str*)path->values[j])->s);
						mkdir(filename,0777);
						chmod(filename,07777);
					}
					else
						sprintf(filename+strlen(filename),"%s",((struct bencode_str*)path->values[j])->s);
				}	
				
				int outfile = open(filename,O_RDWR|O_CREAT,0777);
				if(outfile == -1) {
					fprintf(stderr,"filename: %s\n",filename);
					perror("Couldn't open file for writing");
					exit(1);
				}
				
				int offset_into_file = block_start - accumulated_file_length;
				int remaining_file_length = file_length - offset_into_file;
				lseek(outfile,offset_into_file,SEEK_SET);

				if(remaining_file_length > len) {
					write(outfile,data,len);
					close(outfile);
				}
				else {
					if(debug) {
						fprintf(stderr,"Uh-oh, write crossing file boundaries... watch out!\n");
						fprintf(stderr,"Len %d offset %d filelen %d remaining file len %d\n",len,offset_into_file,file_length,remaining_file_length);
						fflush(stdout);
					}

					write(outfile,data,remaining_file_length);
					close(outfile);
					write_block(data+remaining_file_length,piece,offset+remaining_file_length,len-remaining_file_length,0);
				}

			}
			accumulated_file_length+=file_length;
		}
	}
	// single-file case
	else {
		struct bencode_str* name = (struct bencode_str*)ben_dict_get_by_str(info,"name");
		if(name) {
		  
		  int outfile = open(name->s,O_RDWR|O_CREAT,0777);
      
		  file_length = ((struct bencode_int*)ben_dict_get_by_str(info,"length"))->ll;

		  // write the data to the right spot in the file
		  lseek(outfile,piece*piece_length+offset,SEEK_SET);
		  write(outfile, data,len);
		  close(outfile);
		}
		else {
			printf("No name?\n");
			exit(1);
		}
	}
}