要想实现一个BT下载器,第一步就是解析bt文件:
d
8:announce 37:http://tracker.ktxp.com:6868/announce
13:announce-list
l
l 37:http://tracker.ktxp.com:6868/announce e
l 37:http://tracker.ktxp.com:7070/announce e
l 36:udp://tracker.ktxp.com:6868/announce e
l 36:udp://tracker.ktxp.com:7070/announce e
l 37:http://tracker.dmhy.org:8000/announce e
l 36:udp://tracker.dmhy.org:8000/announce e
l 45:http://tracker.openbittorrent.com:80/announce e
l 39:http://tracker.publicbt.com:80/announce e
l 30:http://tracker.prq.to/announce e
l 36:http://bt.titapark.com:2710/announce e
l 33:http://bt.wiiyi.com:6969/announce e
l 32:http://bt.dmzg.net:6969/announce e
l 34:http://bt.levelup.cn:8080/announce e
l 34:http://bt.levelup.cn:6060/announce e
l 35:http://share.camoe.cn:8080/announce e
l 38:http://tracker.dmguo.com:2710/announce e
l 39:http://tracker.moeing.org:7070/announce e
l 33:http://bt.popgo.net:7456/announce e
e
10:created by 19:BitSpirit/3.6.0.362
13:creation date i 1274740582 e
8:encoding 5:UTF-8
4:info
d
6:length i 113628312 e
4:name 35:[KTXP][KissXsis][08][GB][RV10].rmvb
12:piece length i 131072 e
6:pieces 17340: (17340/20)个哈希值
e
5:nodes
l
l 15:125.201.115.115 i8873e e
l 14:188.222.12.177 i33323e e
l 15:122.116.183.140 i16844e e
l 14:60.241.239.181 i18362e e
l 14:109.204.140.41 i54067e e
l 13:91.126.201.30 i1066e e
e //5:nodes
e //对应文件开始的d
在https://tool.lu/torrent网站计算下info_hash
Hash bbd1454a77291a4987759d4ef7029968870e6000
这个是我整理后的torrent文件,里面有很多信息,例如文件大小,片大小,片数和sha等等;
这个torrent文件采用的是B编码,里面主要就2种基本类型数据,一种是int类型,还有一种就是字符串
其他的有list和dictionary这个我们也按照基本类型数据来解析:
一些公共方法:
int get_digtal_length(int val)
{
int ret=-1;
if(val<10)
return 1;
ret=1;
while(val>10) //12 123
{
ret++;
val/=10;
}
//printf("get_digtal_length=%d\n",ret);
return ret;
}
下面我们来看下解析integer类型的方法:
//content是bt文件拷贝到内存后的首地址
long get_key_value(const char *content,char *des_str,long offset,long *return_val)
{
long read_value;
char *new_offset;
int stringlen;
long tmp;
char *p;
stringlen=strlen(des_str);
//6:lengthi113628312e
if((new_offset=strstr(&content[offset],des_str)) != NULL)
{
tmp=new_offset-content+stringlen;
if(sscanf(&metafile_content[tmp],"i%lde",&read_value)==1)
{
//printf("\n**********get_key_value() new_offset=%d,read_value=%ld ***********\n",tmp,read_value);
*return_val=read_value;
return tmp;
}
printf("\n********** get_key_value() cannot decode,wrong format!!! ***********\n");
return -2;
}
printf("\n********** get_key_value() not found: %s ***********\n",des_str);
*return_val=-1;
return -1;
}
解析字符串方法:
long get_key_string(const char *content,char *des_str,long offset,char *return_str)
{
char *new_offset;
int stringlen;
int length; //键值字符串的长度
long tmp;
stringlen=strlen(des_str);
//printf("get_key_string() find strlen=%d\n",stringlen);
//8:announce37:http://tracker.ktxp.com:6868/announce
if((new_offset=strstr(metafile_content,des_str)) != NULL)
{
tmp=new_offset-metafile_content+stringlen;
if(sscanf(&metafile_content[tmp],"%d:",&length)==1)
{
//printf("get_key_string() length=%d\n",length);
memcpy(return_str,&metafile_content[tmp+get_digtal_length(length)+1],length);
return_str[length]='\0';
return tmp;
}
printf("get_key_string() cannot decode,wrong format!!!\n");
return -2;
}
printf("\n**********get_key_string() not found: %s ***********\n",des_str);
return -1;
}
字符串list类型解析:
/****************************************************
13:announce-list
l
l 37:http://tracker.ktxp.com:6868/announce e
l 37:http://tracker.ktxp.com:7070/announce e
...
e
****************************************************/
int get_list(const char *content,const char *des_str,long offset)//,URL_t *url_list)
{
char *new_offset;
int stringlen,list_str_len;
long tmp;
int i,copyidx=0;
stringlen=strlen(des_str);
if((new_offset=strstr(&content[offset],des_str)) != NULL)
{
tmp=new_offset-content+stringlen;
if(content[tmp++]!='l')
return -2;
while(content[tmp++]=='l')
{
if(sscanf(&metafile_content[tmp],"%d:",&list_str_len)==1)
{
tmp+=get_digtal_length(list_str_len)+1;
memcpy((char *)url[copyidx],&metafile_content[tmp],list_str_len);
url[copyidx][list_str_len]='\0';
}
copyidx++;
tmp+=list_str_len+1; //最后一个+1表示跳过e的意思
}
#if 0 //debug
if(content[--tmp]=='e')
printf("content[tmp]=='e'\n");
#endif
return copyidx;
}
return -1;
}
字符串列表改进版(动态分配):
//保存从torrent文件中获取到tracker的url
typedef struct _Announce_list {
char announce[128];
struct _Announce_list *next;
} Announce_list;
Announce_list *announce_list_head = NULL;
int dynamic_get_list(const char *content,const char *des_str,long offset)
{
char *new_offset;
int stringlen,list_str_len;
long tmp;
int i,cnt=0;
Announce_list *node = NULL;
Announce_list *p = NULL;
stringlen=strlen(des_str);
if((new_offset=strstr(&content[offset],des_str)) != NULL)
{
tmp=new_offset-content+stringlen;
if(content[tmp++]!='l')
return -2;
while(content[tmp++]=='l')
{
if(sscanf(&metafile_content[tmp],"%d:",&list_str_len)==1)
{
tmp+=get_digtal_length(list_str_len)+1;
//过滤掉其他开头的tracker地址
if( memcmp(&metafile_content[tmp],"http",4) == 0 ) {
node = (Announce_list *)malloc(sizeof(Announce_list));
memcpy(node->announce,&metafile_content[tmp],list_str_len);
node->announce[list_str_len] = '\0';
node->next = NULL;
if(announce_list_head == NULL)
announce_list_head = node;
else {
p = announce_list_head;
while( p->next != NULL)
p = p->next;
p->next = node;
}
cnt++;
}
}
tmp+=list_str_len+1; //+1 跳过e
}
#if 0 //debug
if(content[--tmp]=='e')
printf("content[tmp]=='e'\n");
#endif
return cnt;
}
return -1;
}
//打印链表
void print_list(Announce_list *list)
{
Announce_list *p=list;
if(p==NULL)
return;
while(p->next!=NULL)
{
printf("%s\n",p->announce);
p=p->next;
}
printf("\n");
}
每个pieces都有20Byte的sha1:
typedef char (*Hash_t)[20];
Hash_t hash_table,bank_hash_table;
//6:pieces17340:(17340/20)个哈希值
int get_has_array(const char *content,const char *des_str,long offset,int *pieces,Hash_t *hash)
{
char *new_offset;
int stringlen;
long tmp;
int hastable_length;
int i;
stringlen=strlen(des_str);
if((new_offset=strstr(&content[offset],des_str)) != NULL)
{
tmp=new_offset-content+stringlen;
if(sscanf(&metafile_content[tmp],"%d:",&hastable_length)==1)
{
*pieces=hastable_length;
*hash=(Hash_t)malloc(hastable_length);
printf("hash_addr=0x%p\n",*hash);
if(*hash!=NULL)
{
//printf("\n****get_has_array() malloc ok! \n\thastable_length=%ld,offset1=%d",hastable_length,tmp);
tmp+=get_digtal_length(hastable_length)+1;
//printf(",offset2=%d ***********\n",tmp);
//for(i=0;i<16;i++)
// printf("%02X ",(unsigned char)metafile_content[tmp+i]);
//printf("\n");
memcpy((char *)*hash,&metafile_content[tmp],hastable_length);
return tmp;
}
return -3;
}
return -2;
}
return -1;
}