#include "metafile.h"
#include <string.h>
#include <ctype.h>
//定义全局变量
TrackerList *trackerList = NULL;
Files *file = NULL;
char *metafile_buf = NULL; //保存读文种子文件的缓冲区
long long metafile_size; //种子文件长度
char dirname[512]; //目录名称(单文件)
long long filesize; //总的文件大小(多文件则是所有文件大小之和)
long long piece_length; //每个piece的长度
char *pieces_hash = NULL; //保存所有piece hash值的字符串的缓冲区地址
long long pieces_hash_length;
int ismulti_file = 0;//是否为多文件
unsigned char info_hash[20]; //保存info_hash的值,连接tracker和peer使用
unsigned char peer_id[20]; //保存客户端的peer_id
//读取文件到到缓冲区
int readfile_tobuffer(const char *filename)
{
if(filename == NULL){
return -1;
}
long i;
FILE *fp = NULL;
fp = fopen(filename,"rb"); //以二进制形式打开
if(fp == NULL){
printf("open file fail %s:%d\n",__FILE__,__LINE__);
return -1;
}
//获取种子文件长度
fseek(fp,0,SEEK_END); //将文件指针移动到文件尾
metafile_size = ftell(fp);
if(metafile_size == -1){
printf("get metafile size fail %s:%d\n",__FILE__,__LINE__);
return -1;
}
#ifdef DEBUG
printf("metafile size = %lld\n",metafile_size);
#endif
fseek(fp,0,SEEK_SET);//将文件指针移动到文件头
metafile_buf = (char*)malloc(metafile_size+1);
if(metafile_buf == NULL){
printf("malloc fail %s:%d \n",__FILE__,__LINE__);
return -1;
}
memset(metafile_buf,0,metafile_size);
for(i = 0;i < metafile_size;i++)
{
metafile_buf[i] = fgetc(fp);
}
metafile_buf[i] = '\0';
return 0;
}
//在缓冲区中查找指定的字符,返回其地址,找到返回1,没找到返回0,出错返回-1
int find_buf(const char *key,long long *position)
{
if(key == NULL || position == NULL)
{
return -1;
}
*position = -1;
int len = strlen(key);
int i;
for(i = 0;i < metafile_size;i++)
{
if(memcmp(metafile_buf+i,key,len) == 0){
*position = i;
return 1; //找到
}
}
return 0; //没找到
}
//判断是否为多文件
int is_multi_file()
{
long long i;
if(find_buf("5:files",&i) == 1)
{
ismulti_file = 1;
}
#ifdef DEBUG
//printf("multi file = %d\n",ismulti_file);
#endif
return ismulti_file;
}
//保存tracker的url地址到链表
int save_tracker_list()
{
//先查看有没有备用的tracker的URL,有的话直接从announce-list之后开始查找并添加到链表
long long pos = -1;//记录在metafile_buf中的缓冲区的位置
int len = 0; //记录字符串的长度
char tempUrl[512];
memset(tempUrl,0,sizeof(tempUrl));
if(find_buf("d8:announce",&pos) == 1){
if(find_buf("13:announce-list",&pos) == 1){
pos += strlen("13:announce-list");
pos += 2; //跳过2个l
while(metafile_buf[pos] != 'e')
{
len = 0;
while(isdigit(metafile_buf[pos]))
{
len = len*10 + metafile_buf[pos] - '0';
pos++;
}
pos++; //pass :
int i;
for(i = 0;i < len;i++){
tempUrl[i] = metafile_buf[pos++];
}
tempUrl[i+1] = '\0';
//质保存http的url
if(memcmp(tempUrl,"http",4) == 0){
add_tracker_list(tempUrl);
}
pos++; //pass e
if(metafile_buf[pos] == 'l'){
pos++; //pass l
}
}
}else{
//没有备用的tracker的url
pos += strlen("d8:announce");
while(isdigit(metafile_buf[pos]))
{
len = len *10 + metafile_buf[pos] - '0';
pos++;
}
pos++;//滤过:
int i;
for(i = 0;i < len;i++){
tempUrl[i] = metafile_buf[pos++];
}
tempUrl[i+1] = '\0';
//添加到链表节点
add_tracker_list(tempUrl);
}
}else{
printf("parse metafile fail %s:%d\n",__FILE__,__LINE__);
return -1;
}
return 0;
}
//向链表中添加一个url
int add_tracker_list(const char *url)
{
if(url == NULL){
return -1;
}
TrackerList *tracker = (TrackerList *)malloc(sizeof(TrackerList));
if(tracker == NULL){
printf("malloc fail %s:%d\n",__FILE__,__LINE__);
return -1;
}
memcpy(tracker->url,url,strlen(url)+1);
tracker->next = NULL;
if(trackerList == NULL){
trackerList = tracker;
}else{
TrackerList *p = trackerList;
while(p->next != NULL){
p = p->next;
}
p->next = tracker;
}
return 0;
}
//获取文件名和文件大小,如果是多文件获取的是目录名
int get_filepath_name()
{
char filename[1024];
long long pos;
int len = 0;//保存路径名的长度
int len2 = 0;
filesize = 0;
memset(filename,0,sizeof(filename));
//获得目录名
memset(dirname,0,sizeof(dirname));
if(find_buf("4:name",&pos) == 1)
{
pos += strlen("4:name");
while(isdigit(metafile_buf[pos]))
{
len = len*10 + (metafile_buf[pos++] - '0');
}
pos++; //pass :
int i;
for(i = 0;i < len;i++)
{
dirname[i] = metafile_buf[pos++];
}
dirname[i] = '\0';
//判断是否为多问文件
if(is_multi_file() == 0){
//不是多文件,获取文件长度
if(find_buf("6:length",&pos) == 1){
pos += strlen("6:length");
pos++; //跳过i
while(metafile_buf[pos] != 'e' && isdigit(metafile_buf[pos]))
{
filesize = filesize * 10 + (metafile_buf[pos++] - '0');
}
#ifdef DEBUG
printf("single filesize = %lld\n",filesize);
#endif
}
}else{
//多文件模式 filesize 为所有文件大小之和
if(find_buf("5:files",&pos) == 1){
pos += strlen("5:files");
pos++; //pass l
pos++; //pass d
while(metafile_buf[pos] != 'e')
{
len = 0;
len2 = 0;
memset(filename,0,sizeof(filename));
//现获取文件长度
pos += strlen("6:length");
pos++; // pass i
while(isdigit(metafile_buf[pos]) && metafile_buf[pos] != 'e')
{
len = len *10 + (metafile_buf[pos++] - '0');
}
pos++; //pass e
//获取文件路径path
pos += strlen("4:path");
pos++; //pass l
while(isdigit(metafile_buf[pos])){
len2 = len2 *10 + (metafile_buf[pos++] - '0');
}
pos++; //pass :
int i;
for(i = 0; i < len2;i++)
{
filename[i] = metafile_buf[pos++];
}
filename[i] = '\0';
pos += 2;
if(metafile_buf[pos] == 'd')
{
pos++;
}
filesize += len;
//添加到Files链表中
add_toFiles(filename,len);
}
}
}
}
return 0;
}
//添加一个文件信息结构体到文件链表
int add_toFiles(const char *filename,long long len)
{
if(filename == NULL)
return -1;
Files *pfile = (Files *)malloc(sizeof(Files));
if(pfile == NULL){
printf("malloc fail\n",__FILE__,__LINE__);
return -1;
}
memcpy(pfile->filename,filename,strlen(filename)+1);
pfile->filesize = len;
pfile->next = NULL;
if(file == NULL){
file = pfile;
}else{
Files *p = file;
while(p->next){
p = p->next;
}
p->next = pfile;
}
return 0;
}
//获取每个piece的长度
int get_piece_length()
{
long long pos;
piece_length = 0;
if(find_buf("12:piece length",&pos) == 1){
pos += strlen("12:piece length");
pos++; //pass i
while(isdigit(metafile_buf[pos])&&(metafile_buf[pos] != 'e'))
{
piece_length = piece_length *10 + (metafile_buf[pos++] - '0');
}
}else{
printf("get piece_length fail %s:%d\n",__FILE__,__LINE__);
return -1;
}
return 0;
}
//获取pieces的hash值,保存到缓冲区中
int get_pieces_hash()
{
//先获取hash值的字符串长度
pieces_hash_length = 0;
long long pos;
if(find_buf("6:pieces",&pos) == 1)
{
pos += strlen("6:pieces");
while(metafile_buf[pos] != ':') //数字以:结束
{
pieces_hash_length = pieces_hash_length*10 + (metafile_buf[pos++] - '0');
}
#ifdef DEBUG
printf("pieces hash = %lld\n",pieces_hash_length);
#endif
pieces_hash = (char *)malloc(pieces_hash_length+1);
if(pieces_hash == NULL){
printf("malloc fial %s:%d \n",__FILE__,__LINE__);
return -1;
}
memset(pieces_hash,0,sizeof(pieces_hash));
pos++; //pass :
long i;
for(i = 0;i < pieces_hash_length ;i++){
pieces_hash[i] = metafile_buf[pos++];
}
pieces_hash[i] = '\0';
}
return 0;
}
// 计算info_hash的值
int cal_info_hash()
{
//找到4:info后面的字典d的结束标记e
long long begin,end,pos;
int push_pop = 0; //用于标记,找到d对应的e
//查找4:info
if(find_buf("4:info",&pos) == 1){
pos += strlen("4:info");
begin = pos; //记录info关键字对应值的开始位置
do{
if(metafile_buf[pos] == 'd'){ //字典开头
push_pop++;
pos++;
}
else if(isdigit(metafile_buf[pos]))
{
int i = 0;
//如果是数字,说明后面跟一个字符串 5:files 跳过:和字符串
while(isdigit(metafile_buf[pos])){
i = i * 10 + (metafile_buf[pos++] - '0');
}
pos++; //pass:
pos += i;
//printf("***%c\n",metafile_buf[pos]);
}
else if(metafile_buf[pos] == 'l') //列表开头
{
push_pop++;
pos++;
}
else if(metafile_buf[pos] == 'i' && isdigit(metafile_buf[pos+1])) //说明是数字
{
push_pop++;
pos++; //pass:i
while(isdigit(metafile_buf[pos])){
//跳过i和e之间的数字
pos++;
}
// printf("***%c\n",metafile_buf[pos]);
// printf("push_pop = %d\n",push_pop);
}
else if(metafile_buf[pos == 'e']){ //如果是e push_pop-1
push_pop--;
pos++;
}
}while(push_pop > 0);
//退出循环pos指向e的下一个字符
end = pos -1;
#ifdef DEBUG
printf("begin = %c,end = %c,pos = %c\n",metafile_buf[begin],metafile_buf[end],metafile_buf[pos]);
#endif
//计算info 对应信息的hash值,保存到info_hash中,用于连接tracker和peer
memset(info_hash,0,sizeof(info_hash));
SHA1_CTX context;
SHA1Init(&context);
SHA1Update(&context,&metafile_buf[begin],end-begin+1);
SHA1Final(info_hash,&context);
#ifdef DEBUG
printf("info_hash: ");
int j = 0;
for(;j<20;j++){
printf("%.2x",info_hash[j]);
}
printf("\n");
#endif
}else{
printf("get info_hash fail %s:%d\n",__FILE__,__LINE__);
return -1;
}
return 0;
}
//生成唯一的一个peer_id来标识客户端,peer_id前八位固定-TT1000-
int get_peer_id()
{
//设置随机数种子
srand(time(NULL));
sprintf(peer_id,"-TT1000-%12d",rand());
#ifdef DEBUG
printf("peer_id: %s\n",peer_id);
#endif
return 0;
}
//释放动态内存
void release_memory()
{
TrackerList *pTracker = trackerList,*p = NULL;
Files *pFile = file , *q = NULL;
while(pTracker){
p = pTracker->next;
free(pTracker);
pTracker = p;
}
trackerList = NULL;
while(pFile)
{
q = pFile->next;
free(pFile);
pFile = q;
}
file = NULL;
if(metafile_buf){
free(metafile_buf);
metafile_buf = NULL;
}
if(pieces_hash){
free(pieces_hash);
pieces_hash = NULL;
}
}
//种子文件解析模块
int parse_metafile(const char * metafile_name)
{
if(metafile_name == NULL)
return -1;
//读取种子文件到缓冲区
if(readfile_tobuffer(metafile_name) < 0){
printf("error : %s:%d\n",__FILE__,__LINE__);return -1;}
//保存tracker的url地址到链表
if(save_tracker_list() < 0){
printf("error : %s:%d\n",__FILE__,__LINE__);return -1;}
//获取文件名和文件大小,如果是多文件获取的是目录名
if(get_filepath_name() < 0){
printf("error : %s:%d\n",__FILE__,__LINE__);return -1;}
//获取每个piece的长度
if(get_piece_length() < 0){
printf("error : %s:%d\n",__FILE__,__LINE__);return -1;}
//获取pieces的hash值,保存到缓冲区中
if(get_pieces_hash() < 0){
printf("error : %s:%d\n",__FILE__,__LINE__);return -1;}
// 计算info_hash的值
if(cal_info_hash() < 0){
printf("error : %s:%d\n",__FILE__,__LINE__);return -1;}
//生成唯一的一个peer_id来标识客户端
if(get_peer_id() < 0){
printf("error : %s:%d\n",__FILE__,__LINE__);return -1;}
//释放动态内存
release_memory();
return 0;
}
//test1
void test1()
{
TrackerList *p = trackerList;
while(p){
printf("%s\n",p->url);
p = p->next;
}
}
//test2()
void test2()
{
printf("dirpath = %s\n",dirname);
//输出文件信息
if(is_multi_file()){
Files *p = file;
while(p){
printf("filename = %s,filesize = %ld\n",p->filename,p->filesize);
p = p ->next;
}
}else{
printf("single filesize = %lld\n",filesize);
}
printf("piece_length = %lld\n",piece_length);
printf("total filesize = %lld\n",filesize);
}
void test3()
{
long i;
for(i = 0; i < pieces_hash_length;i++)
{
printf("%0x",pieces_hash[i]);
if(i%20 == 0 && i!= 0){
printf("\n");
break;
}
}
}
void test4()
{
cal_info_hash();
get_peer_id();
}
[文件] sha1.c ~ 5KB 下载(24)
#include <string.h>
#include "sha1.h"
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
/* blk0() and blk() perform the initial expand. */
/* I got the idea of expanding during the round function from SSLeay */
#if (defined(BYTE_ORDER) && BYTE_ORDER==LITTLE_ENDIAN) || (!defined(BYTE_ORDER) && defined(LITTLE_ENDIAN))
#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
|(rol(block->l[i],8)&0x00FF00FF))
#else
#define blk0(i) block->l[i]
#endif
#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
^block->l[(i+2)&15]^block->l[i&15],1))
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
/* Hash a single 512-bit block. This is the core of the algorithm. */
void SHA1Transform(unsigned long state[5], unsigned char buffer[64])
{
unsigned long a, b, c, d, e;
typedef union {
unsigned char c[64];
unsigned long l[16];
} CHAR64LONG16;
CHAR64LONG16* block;
#ifdef SHA1HANDSOFF
static unsigned char workspace[64];
block = (CHAR64LONG16*)workspace;
memcpy(block, buffer, 64);
#else
block = (CHAR64LONG16*)buffer;
#endif
/* Copy context->state[] to working vars */
a = state[0];
b = state[1];
c = state[2];
d = state[3];
e = state[4];
/* 4 rounds of 20 operations each. Loop unrolled. */
R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
/* Add the working vars back into context.state[] */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
state[4] += e;
/* Wipe variables */
a = b = c = d = e = 0;
}
/* SHA1Init - Initialize new context */
void SHA1Init(SHA1_CTX* context)
{
/* SHA1 initialization constants */
context->state[0] = 0x67452301;
context->state[1] = 0xEFCDAB89;
context->state[2] = 0x98BADCFE;
context->state[3] = 0x10325476;
context->state[4] = 0xC3D2E1F0;
context->count[0] = context->count[1] = 0;
}
/* Run your data through this. */
void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len)
{
unsigned int i, j;
j = (context->count[0] >> 3) & 63;
if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
context->count[1] += (len >> 29);
if ((j + len) > 63) {
memcpy(&context->buffer[j], data, (i = 64-j));
SHA1Transform(context->state, context->buffer);
for ( ; i + 63 < len; i += 64) {
SHA1Transform(context->state, &data[i]);
}
j = 0;
}
else i = 0;
memcpy(&context->buffer[j], &data[i], len - i);
}
/* Add padding and return the message digest. */
void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
{
unsigned long i, j;
unsigned char finalcount[8];
for (i = 0; i < 8; i++) {
finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
>> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
}
SHA1Update(context, (unsigned char *)"\200", 1);
while ((context->count[0] & 504) != 448) {
SHA1Update(context, (unsigned char *)"\0", 1);
}
SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
for (i = 0; i < 20; i++) {
digest[i] = (unsigned char)
((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
}
/* Wipe variables */
i = j = 0;
memset(context->buffer, 0, 64);
memset(context->state, 0, 20);
memset(context->count, 0, 8);
memset(&finalcount, 0, 8);
#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */
SHA1Transform(context->state, context->buffer);
#endif
}