⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 common.c

📁 elinks下lynx是最重要的二个文本浏览器, 在linux下非常实用, elinks也是gentoo安装过程中默认使用的浏览器, 这是elinks源代码
💻 C
字号:
/* Library of common BitTorrent code */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <stdlib.h>#include <string.h>#include "elinks.h"#include "main/select.h"#include "network/connection.h"#include "protocol/bittorrent/common.h"#include "session/download.h"#include "util/conv.h"#include "util/error.h"#include "util/lists.h"#include "util/memory.h"#include "util/sha1.h"#include "util/string.h"#include "util/snprintf.h"/* Debug function which returns printable peer ID. */unsigned char *get_peer_id(bittorrent_id_T peer_id){	static unsigned char hex[41];	int i, j;	if (bittorrent_id_is_empty(peer_id)) {		snprintf(hex, sizeof(hex), "unknown id %p", peer_id);		return hex;	}	for (i = 0, j = 0; i < sizeof(bittorrent_id_T); i++, j++) {		unsigned char value = peer_id[i];		if (isprint(value)) {			hex[j] = value;		} else {			hex[j++]   = hx(value >> 4 & 0xF);			hex[j] = hx(value & 0xF);		}	}	hex[j] = 0;	return hex;}unsigned char *get_peer_message(enum bittorrent_message_id message_id){	static struct {		enum bittorrent_message_id message_id;		unsigned char *name;	} messages[] = {		{ BITTORRENT_MESSAGE_INCOMPLETE,	"incomplete"	 },		{ BITTORRENT_MESSAGE_KEEP_ALIVE,	"keep-alive"	 },		{ BITTORRENT_MESSAGE_CHOKE,		"choke"		 },		{ BITTORRENT_MESSAGE_UNCHOKE,		"unchoke"	 },		{ BITTORRENT_MESSAGE_INTERESTED,	"interested"     },		{ BITTORRENT_MESSAGE_NOT_INTERESTED,	"not-interested" },		{ BITTORRENT_MESSAGE_HAVE,		"have"		 },		{ BITTORRENT_MESSAGE_BITFIELD,		"bitfield"	 },		{ BITTORRENT_MESSAGE_REQUEST,		"request"	 },		{ BITTORRENT_MESSAGE_PIECE,		"piece"		 },		{ BITTORRENT_MESSAGE_CANCEL,		"cancel"	 },		{ 0, NULL },	};	int i;	for (i = 0; messages[i].name; i++)		if (messages[i].message_id == message_id)			return messages[i].name;	return "unknown";}unsigned char *get_hexed_bittorrent_id(bittorrent_id_T id){	static unsigned char hex[SHA_DIGEST_LENGTH * 2 + 1];	int i;	for (i = 0; i < sizeof(bittorrent_id_T); i++) {		int j = i * 2;		hex[j++] = hx(id[i] >> 4 & 0xF);		hex[j]   = hx(id[i] & 0xF);	}	hex[SHA_DIGEST_LENGTH * 2] = 0;	return hex;}intbittorrent_piece_is_valid(struct bittorrent_meta *meta,			  uint32_t piece, unsigned char *data, uint32_t datalen){	unsigned char *piece_hash;	bittorrent_id_T data_hash;	assert(piece < meta->pieces);	SHA1(data, datalen, data_hash);	piece_hash = &meta->piece_hash[piece * SHA_DIGEST_LENGTH];	return !memcmp(data_hash, piece_hash, SHA_DIGEST_LENGTH);}voiddone_bittorrent_meta(struct bittorrent_meta *meta){	free_uri_list(&meta->tracker_uris);	mem_free_if(meta->name);	mem_free_if(meta->comment);	mem_free_if(meta->piece_hash);	free_list(meta->files);}voiddone_bittorrent_message(struct bittorrent_message *message){	del_from_list(message);	done_uri(message->uri);	mem_free(message);}/* ************************************************************************** *//* Peer information management: *//* ************************************************************************** *//* Generate a peer ID with of the form: 'E' <version> '-' <random> */voidinit_bittorrent_peer_id(bittorrent_id_T peer_id){	unsigned char *version = VERSION;	int dots = 0;	int i = 0;	srand(time(NULL));	peer_id[i++] = 'E';	peer_id[i++] = 'L';	for (; *version && i < sizeof(bittorrent_id_T); version++) {		if (isdigit(*version)) {			peer_id[i++] = *version;		} else if (*version == '.' && !dots) {			dots = 1;		} else {			peer_id[i++] = '-';			break;		}		peer_id[i++] = *version;	}	/* Hmm, sizeof(peer_id) don't work here. */	while (i < sizeof(bittorrent_id_T)) {		int random = rand();		while (i < sizeof(bittorrent_id_T) && (random & 0xF)) {			peer_id[i++] = hx(random & 0xF);			random >>= 4;		}	}}intbittorrent_id_is_known(struct bittorrent_connection *bittorrent,		       bittorrent_id_T id){	struct bittorrent_peer_connection *peer;	/* The peer ID matches the client ID? */	if (!memcmp(bittorrent->peer_id, id, sizeof(bittorrent->peer_id)))		return 1;	foreach (peer, bittorrent->peers)		if (!memcmp(peer->id, id, sizeof(peer->id)))			return 1;	if (get_peer_from_bittorrent_pool(bittorrent, id))		return 1;	return 0;}struct bittorrent_peer *get_peer_from_bittorrent_pool(struct bittorrent_connection *bittorrent,			      bittorrent_id_T id){	struct bittorrent_peer *peer_info;	foreach (peer_info, bittorrent->peer_pool)		if (!memcmp(peer_info->id, id, sizeof(peer_info->id)))			return peer_info;	return NULL;}enum bittorrent_stateadd_peer_to_bittorrent_pool(struct bittorrent_connection *bittorrent,			    bittorrent_id_T id, int port,			    unsigned char *ip, int iplen){	struct bittorrent_peer *peer;	/* Check sanity. Don't error out here since entries in the tracker	 * responses can contain garbage and we don't want to bring down the	 * whole connection for that. */	if (iplen <= 0 || !uri_port_is_valid(port))		return BITTORRENT_STATE_OK;	/* The ID can be NULL for the compact format. */	if (id) {		enum bittorrent_blacklist_flags flags;		if (bittorrent_id_is_empty(id))			return BITTORRENT_STATE_ERROR;		/* Check if the peer is already known. */		if (bittorrent_id_is_known(bittorrent, id))			return BITTORRENT_STATE_OK;		flags = get_bittorrent_blacklist_flags(id);		if (flags != BITTORRENT_BLACKLIST_NONE)			return BITTORRENT_STATE_OK;	}	/* Really add the peer. */	peer = mem_calloc(1, sizeof(*peer) + iplen);	if (!peer) return BITTORRENT_STATE_OUT_OF_MEM;	peer->port = port;	if (iplen) memcpy(peer->ip, ip, iplen);	if (id) memcpy(peer->id, id, sizeof(peer->id));	add_to_list(bittorrent->peer_pool, peer);	return BITTORRENT_STATE_OK;}/* ************************************************************************** *//* Peer request management: *//* ************************************************************************** */struct bittorrent_peer_request *get_bittorrent_peer_request(struct bittorrent_peer_status *status,			    uint32_t piece, uint32_t offset, uint32_t length){	struct bittorrent_peer_request *request;	foreach (request, status->requests)  {		if (request->piece == piece		    && request->offset == offset		    && request->length == length)			return request;	}	return NULL;}voidadd_bittorrent_peer_request(struct bittorrent_peer_status *status,			    uint32_t piece, uint32_t offset, uint32_t length){	struct bittorrent_peer_request *request;	request = get_bittorrent_peer_request(status, piece, offset, length);	if (request) return;	request = mem_alloc(sizeof(*request));	if (!request) return;	request->piece	= piece;	request->offset	= offset;	request->length	= length;	/* FIXME: Rather insert the request so that we atleast try to get	 * some sort of sequential access to piece data. */	add_to_list_end(status->requests, request);}voiddel_bittorrent_peer_request(struct bittorrent_peer_status *status,			    uint32_t piece, uint32_t offset, uint32_t length){	struct bittorrent_peer_request *request;	request = get_bittorrent_peer_request(status, piece, offset, length);	if (!request) return;	del_from_list(request);	mem_free(request);}/* ************************************************************************** *//* Generic URI downloader: *//* ************************************************************************** */struct bittorrent_fetcher {	struct bittorrent_fetcher **ref;	bittorrent_fetch_callback_T callback;	void *data;	int redirects;	unsigned int delete:1;	struct download download;};/* This part of the code is very lowlevel and ELinks specific. The download * callback is called each time there is some progress, such as new data. So * first it basically checks the state and tries to handle it accordingly. * Redirects are also handled here. */static voidbittorrent_fetch_callback(struct download *download, void *data){	struct bittorrent_fetcher *fetcher = data;	struct fragment *fragment;	struct string response;	struct cache_entry *cached = download->cached;	/* If the callback was removed we should shutdown ASAP. */	if (!fetcher->callback || download->state == S_INTERRUPTED) {		if (download->state == S_INTERRUPTED)			mem_free(fetcher);		return;	}	if (is_in_result_state(download->state) && download->state != S_OK) {		fetcher->callback(fetcher->data, download->state, NULL);		if (fetcher->ref)			*fetcher->ref = NULL;		mem_free(fetcher);		return;	}	if (!cached || is_in_queued_state(download->state))		return;	if (cached->redirect && fetcher->redirects++ < MAX_REDIRECTS) {		if (is_in_progress_state(download->state))			change_connection(download, NULL, PRI_CANCEL, 0);		download->state = S_WAIT_REDIR;		load_uri(cached->redirect, cached->uri, download,			 PRI_DOWNLOAD, CACHE_MODE_NORMAL,			 download->progress ? download->progress->start : 0);		return;	}	if (is_in_progress_state(download->state))		return;	assert(download->state == S_OK);	/* If the entry is chunked defragment it and grab the single, remaining	 * fragment. */	fragment = get_cache_fragment(cached);	if (!fragment) {		fetcher->callback(fetcher->data, S_OUT_OF_MEM, NULL);		if (fetcher->ref)			*fetcher->ref = NULL;		mem_free(fetcher);		return;	}	response.source = fragment->data;	response.length = fragment->length;	fetcher->callback(fetcher->data, S_OK, &response);	if (fetcher->delete)		delete_cache_entry(cached);	if (fetcher->ref)		*fetcher->ref = NULL;	mem_free(fetcher);}struct bittorrent_fetcher *init_bittorrent_fetch(struct bittorrent_fetcher **fetcher_ref,		      struct uri *uri, bittorrent_fetch_callback_T callback,		      void *data, int delete){	struct bittorrent_fetcher *fetcher;	fetcher = mem_calloc(1, sizeof(*fetcher));	if (!fetcher) {		callback(data, S_OUT_OF_MEM, NULL);		return NULL;	}	if (fetcher_ref)		*fetcher_ref = fetcher;	fetcher->ref		   = fetcher_ref;	fetcher->callback	   = callback;	fetcher->data		   = data;	fetcher->delete		   = delete;	fetcher->download.callback = bittorrent_fetch_callback;	fetcher->download.data     = fetcher;	load_uri(uri, NULL, &fetcher->download, PRI_MAIN, CACHE_MODE_NORMAL, -1);	return fetcher;}static voidend_bittorrent_fetch(void *fetcher_data){	struct bittorrent_fetcher *fetcher = fetcher_data;	assert(fetcher && !fetcher->callback);	/* Stop any running connections. */	if (is_in_progress_state(fetcher->download.state))		change_connection(&fetcher->download, NULL, PRI_CANCEL, 0);	mem_free(fetcher);}voiddone_bittorrent_fetch(struct bittorrent_fetcher **fetcher_ref){	struct bittorrent_fetcher *fetcher;	assert(fetcher_ref);	fetcher = *fetcher_ref;	*fetcher_ref = NULL;	assert(fetcher);	if (fetcher->ref)		*fetcher->ref = NULL;	/* Nuke the callback so nothing gets called */	fetcher->callback = NULL;	register_bottom_half(end_bittorrent_fetch, fetcher);}/* ************************************************************************** *//* Blacklist management: *//* ************************************************************************** */struct bittorrent_blacklist_item {	LIST_HEAD(struct bittorrent_blacklist_item);	enum bittorrent_blacklist_flags flags;	bittorrent_id_T id;};static INIT_LIST_HEAD(bittorrent_blacklist);static struct bittorrent_blacklist_item *get_bittorrent_blacklist_item(bittorrent_id_T peer_id){	struct bittorrent_blacklist_item *item;	foreach (item, bittorrent_blacklist)		if (!memcmp(item->id, peer_id, sizeof(bittorrent_id_T)))			return item;	return NULL;}voidadd_bittorrent_blacklist_flags(bittorrent_id_T peer_id,			       enum bittorrent_blacklist_flags flags){	struct bittorrent_blacklist_item *item;	item = get_bittorrent_blacklist_item(peer_id);	if (item) {		item->flags |= flags;		return;	}	item = mem_calloc(1, sizeof(*item));	if (!item) return;	item->flags = flags;	memcpy(item->id, peer_id, sizeof(bittorrent_id_T));	add_to_list(bittorrent_blacklist, item);}voiddel_bittorrent_blacklist_flags(bittorrent_id_T peer_id,			       enum bittorrent_blacklist_flags flags){	struct bittorrent_blacklist_item *item;	item = get_bittorrent_blacklist_item(peer_id);	if (!item) return;	item->flags &= ~flags;	if (item->flags) return;	del_from_list(item);	mem_free(item);}enum bittorrent_blacklist_flagsget_bittorrent_blacklist_flags(bittorrent_id_T peer_id){	struct bittorrent_blacklist_item *item;	item = get_bittorrent_blacklist_item(peer_id);	return item ? item->flags : BITTORRENT_BLACKLIST_NONE;}voiddone_bittorrent_blacklist(void){	free_list(bittorrent_blacklist);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -