#ifndef EL__PROTOCOL_BITTORRENT_PIECECACHE_H #define EL__PROTOCOL_BITTORRENT_PIECECACHE_H #include "protocol/bittorrent/common.h" #include "util/lists.h" #ifdef __cplusplus extern "C" { #endif struct bitfield; struct bittorrent_piece_cache_entry { LIST_HEAD_EL(struct bittorrent_piece_cache_entry); /** Piece rarity index * To keep track of the client's view of the swarm in regards to pieces a * piece rarity index for neighboring peers is maintained for each piece * in the torrent. It keeps track of how many neighboring peers have the * piece. The smaller the value the more rare the piece is. The table is * updated when the client receives bitfield or have messages. Zero * indicates that no neightboring peer has the piece. */ uint16_t rarity; unsigned int completed:1; /**< All blocks was downloaded. */ unsigned int remaining:1; /**< Nothing has been even requested. */ unsigned int locked:1; /**< Edge piece from partial downloads. */ unsigned int selected:1; /**< Piece is part of partial download. */ /** A bitfield of the blocks which remains to be downloaded for this * piece. May be NULL if downloading is not in progress. */ struct bitfield *blocks; /** The data of the piece. * May be NULL if data has not been downloaded * or the piece has been written to disk. * XXX: This memory is mmaped using the mem_mmap_*() functions. */ char *data; }; struct bittorrent_piece_cache { /* The following is mostly maintained for making it easy to display in * dialogs. */ unsigned int remaining_pieces; /**< Number of untouched pieces */ unsigned int completed_pieces; /**< Number of downloaded pieces */ unsigned int loading_pieces; /**< Number of pieces in progress */ unsigned int rejected_pieces; /**< Number of hash check rejects */ unsigned int unavailable_pieces;/**< Number of unavailable pieces */ unsigned int partial_pieces; /**< Number of selected file pieces */ unsigned int locked_pieces; /**< Pieces locked due to partial download */ /* Flags set from the download dialog. */ unsigned int delete_files:1; /**< Unlink files on shutdown? */ unsigned int notify_complete:1; /**< Notify upon completion? */ unsigned int partial:1; /**< Dealing with a partial download? */ /** The pipe descripter used for communicating with the resume thread. */ int resume_fd; uint32_t resume_pos; /** A bitfield of the available pieces. */ struct bitfield *bitfield; /** A list of completed and saved entries which has been loaded into * memory. The allocated memory for all these entries is disposable. The * entries are sorted in a LRU-manner. */ LIST_OF(struct bittorrent_piece_cache_entry) queue; /** Remaining pieces are tracked using the remaining_blocks member of the * piece cache entry and a free list of piece blocks to be requested. * Requests are taken from the free list every time a peer queries which * piece block to request next. If the piece list is empty (or if the * remote peer does not have any of the pieces currently in the free * list) the cache is searched for a remaining piece and any found piece * is then broken into a number of requests. Typically, the querying * peer will only add a few of the requests to its queue so the rest of * the requests will end up in the free list. This way more than one * peer can request blocks from the same piece and the overall strategy * will try to finish already started pieces before it begins * downloading of new ones. * * When the free list is empty _and_ the number of remaining pieces is * zero the client enters the end game mode. That is, _all_ remaining * requests are _pending_. To speed up the end game mode, more than one * peer is allowed to request the same piece, however, it is important * to cancel these requests when they are completed to not waste * bandwitdth. To ease canceling in end game mode peer requests has a * cloned flag. The flag is set when piece block requests are cloned. If * the cloned flag is set when receiving a block then the peer-list is * searched and requests for the same piece is canceled. */ LIST_OF(struct bittorrent_piece_request) free_list; struct bittorrent_piece_cache_entry entries[1]; }; enum bittorrent_state init_bittorrent_piece_cache(struct bittorrent_connection *bittorrent, struct bittorrent_const_string *metafile); void done_bittorrent_piece_cache(struct bittorrent_connection *bittorrent); void update_bittorrent_piece_cache_state(struct bittorrent_connection *bittorrent); /* Depending on the current download mode, try to find a block to request. */ struct bittorrent_peer_request * find_bittorrent_peer_request(struct bittorrent_peer_connection *peer); void add_requests_to_bittorrent_piece_cache(struct bittorrent_peer_connection *peer, struct bittorrent_peer_status *status); void update_bittorrent_piece_cache(struct bittorrent_peer_connection *peer, uint32_t piece); void update_bittorrent_piece_cache_from_bitfield(struct bittorrent_peer_connection *peer); void remove_bittorrent_peer_from_piece_cache(struct bittorrent_peer_connection *peer); enum bittorrent_state add_to_bittorrent_piece_cache(struct bittorrent_peer_connection *peer, uint32_t piece, uint32_t offset, char *data, uint32_t datalen, int *write_errno); char * get_bittorrent_piece_cache_data(struct bittorrent_connection *bittorrent, uint32_t piece); #ifdef __cplusplus } #endif #endif