void check_parse(char* fileName) { //http://sourceforge.net/p/funzix/code/ci/master/tree/bencode/test.c#l43 char *buf; long long len; be_node *n; buf = read_file(fileName, &len); if (!buf) { buf = fileName; len = strlen(fileName); } printf("DECODING: %s\n", fileName); n = be_decoden(buf, len); if (n) { be_dump(n); be_free(n); } else printf("\tparsing failed!\n"); #ifdef FILE_IO if (buf != fileName) free(buf); #endif return; }
/* USAGE: decode(FILE) * */ bendecoded *decode(char *file) { char *buf; long long len; be_node *n; buf = read_file(file, &len); printf("DECODING: %s\n", file); n = be_decoden(buf, len); if(!n) { printf("\tparsing failed!\n"); } bendecoded *output = decoded(n); unsigned char *info_hash; get_info_hash(&info_hash); printf("announce: %s\n", output->announce); printf("creation date: %lli\n", output->creation_date); printf("created by: %s\n", output->created_by); printf("encoding: %s\n", output->encoding); printf("info -> piece length: %lli\n", output->info->piece_length); printf("info -> pieces: %s\n", output->info->pieces); printf("info -> name: %s\n", output->info->name); printf("(assuming single file mode for now)\n"); printf("info -> length: %lli\n", output->info->length); printf("info -> md5sum: %s\n", output->info->md5sum); printf("info_hash before sha1 is: %s\n", info_hash); free(buf); //be_dump(n); //be_free(n); return output; }
be_node * load_be_node(char * torf){ char * torf_d; //stores the raw data of the torrent file long long torf_s;//size of the torrent file be_node * node; //store the top node in the bencoding of the torrent file torf_d = _read_file(torf,&torf_s); node = be_decoden(torf_d,torf_s); free(torf_d); //free the raw torrent file, not needed anymore return node; }
rss_body *parse_bencode_from_file(const char *filename) { be_node *node; char *contents = 0; unsigned int length = read_file(filename, &contents); if ((node = be_decoden(contents, length))) { return handle_body(node); } else { return NULL; } }
// 解码B编码的数据, 将解码后的数据放入tracker_data结构 tracker_data* get_tracker_data(char* data, int len) { tracker_data* ret; be_node* ben_res; printf("data: %s\n", data); printf("len: %d\n", len); ben_res = be_decoden(data, len); printf("be_decoden\n"); printf("len: %d\n", len); printf("BE_DICT: %d\n", BE_DICT); printf("type: %d\n", ben_res->type);//type总出问题,往往是信息没有正确读取 if(ben_res->type != BE_DICT) { perror("Data not of type dict"); exit(-12); } ret = (tracker_data*)malloc(sizeof(tracker_data)); if(ret == NULL) { perror("Could not allcoate tracker_data"); exit(-12); } // 遍历键并测试它们 int i; for (i = 0; ben_res->val.d[i].val != NULL; i++) { // 检查是否有失败键 printf("key: %s\n", ben_res->val.d[i].key); if(strncmp(ben_res->val.d[i].key, "failure reason", strlen("failure reason")) == 0) { printf("Error: %s",ben_res->val.d[i].val->val.s); exit(-12); } printf("======interval======\n"); // interval键 if(strncmp(ben_res->val.d[i].key,"interval",strlen("interval")) == 0) { ret->interval = (int)ben_res->val.d[i].val->val.i; printf("interval: %d\n", ret->interval); } // peers键 printf("======peers======\n"); if(strncmp(ben_res->val.d[i].key,"peers",strlen("peers")) == 0) { be_node* peer_list = ben_res->val.d[i].val; get_peers(ret, peer_list); } } be_free(ben_res); return ret; }
be_node * load_be_node(char * torf, char ** file){ char * torf_d; //stores the raw data of the torrent file long long torf_s; be_node * node; //store the top node in the bencoding of the torrent file torf_d = _read_file(torf,&torf_s); if(file!=NULL){ *file = _read_file(torf,&torf_s); } //printf("%s\n",torf_d ); //printf("%s\n", *file ); node = be_decoden(torf_d,torf_s); free(torf_d); //free the raw torrent file, not needed anymore return node; }
// 解码B编码的数据, 将解码后的数据放入tracker_data结构 tracker_data* get_tracker_data(char* data, int len) { tracker_data* ret; be_node* ben_res; ben_res = be_decoden(data,len); if(ben_res->type != BE_DICT) { perror("Data not of type dict"); exit(-12); } ret = (tracker_data*)malloc(sizeof(tracker_data)); if(ret == NULL) { perror("Could not allcoate tracker_data"); exit(-12); } // 遍历键并测试它们 int i; for (i=0; ben_res->val.d[i].val != NULL; i++) { //printf("%s\n",ben_res->val.d[i].key); // 检查是否有失败键 if(!strncmp(ben_res->val.d[i].key,"failure reason",strlen("failure reason"))) { printf("Error: %s",ben_res->val.d[i].val->val.s); exit(-12); } // interval键 if(!strncmp(ben_res->val.d[i].key,"interval",strlen("interval"))) { ret->interval = (int)ben_res->val.d[i].val->val.i; } // peers键 if(!strncmp(ben_res->val.d[i].key,"peers",strlen("peers"))) { be_node* peer_list = ben_res->val.d[i].val; get_peers(ret,peer_list); } } be_free(ben_res); return ret; }
trg_torrent_file *trg_parse_torrent_data(const gchar *data, gsize length) { trg_torrent_file *ret = NULL; be_node *top_node, *info_node, *name_node; top_node = be_decoden(data, length); if (!top_node) { return NULL; } else if (!be_validate_node(top_node, BE_DICT)) { goto out; } info_node = be_dict_find(top_node, "info", BE_DICT); if (!info_node) goto out; name_node = be_dict_find(info_node, "name", BE_STR); if (!name_node) goto out; ret = g_new0(trg_torrent_file, 1); ret->name = g_strdup(name_node->val.s); ret->top_node = trg_parse_torrent_file_nodes(info_node); if (!ret->top_node) { trg_files_tree_node *file_node; be_node *length_node = be_dict_find(info_node, "length", BE_INT); if (!length_node) { g_free(ret); ret = NULL; goto out; } file_node = g_new0(trg_files_tree_node, 1); file_node->length = (gint64) (length_node->val.i); file_node->name = g_strdup(ret->name); ret->top_node = file_node; } out: be_free(top_node); return ret; }
int main(int argc, char ** argv) { int i; be_node * ben_res; FILE * f; int flen; char * data; f = fopen(argv[1], "r"); if (!f) { printf("file open fail\n"); exit(1); } flen = file_len(f); data = (char *) malloc ( sizeof(char) * flen ); fread(data, sizeof(char), flen, f); fclose(f); ben_res = be_decoden(data, flen); printfile(ben_res, 0); return 0; }
be_node *be_decode(const char *data) { return be_decoden(data, strlen(data)); }
int CFileSystem::validatePool(const std::string& path) { if(!directoryExists(path)) { LOG_ERROR("Pool directory doesn't exist: %s", path.c_str()); return 0; } int res=0; std::list <std::string>dirs; dirs.push_back(path); int maxdirs=257; //FIXME: unknown dirs in pool will break bar int finished=0; IHash* md5=new HashMD5(); while(!dirs.empty()) { struct dirent* dentry; DIR* d; const std::string dir=dirs.front(); dirs.pop_front(); d=opendir(dir.c_str()); while ( (dentry=readdir(d))!=NULL) { LOG_PROGRESS(finished, maxdirs); std::string absname=dir; absname += PATH_DELIMITER; absname += dentry->d_name; if (dentry->d_name[0]!='.') { //don't check hidden files / . / .. #ifndef WIN32 if ((dentry->d_type & DT_DIR)!=0) { //directory #else struct stat sb; stat(absname.c_str(), &sb); if((sb.st_mode & S_IFDIR)!=0) { #endif dirs.push_back(absname); } else { FileData filedata=FileData(); int len=absname.length(); if (len<36) { //file length has at least to be <md5[0]><md5[1]>/<md5[2-30]>.gz LOG_ERROR("Invalid file: %s", absname.c_str()); } else { std::string md5str=""; md5str.push_back(absname.at(len-36)); //get md5 from path + filename md5str.push_back(absname.at(len-35)); md5str.append(absname.substr(len-33, 30)); md5->Set(md5str); for(unsigned i=0; i<16; i++) { filedata.md5[i]=md5->get(i); } if (!fileIsValid(&filedata, absname)) { //check if md5 in filename is the same as in filename LOG_ERROR("Invalid File in pool: %s",absname.c_str()); } else { res++; } } } } } finished++; closedir(d); } delete md5; LOG_PROGRESS(finished, maxdirs, true); LOG(""); return res; } bool CFileSystem::isOlder(const std::string& filename, int secs) { struct stat sb; if (stat(filename.c_str(),&sb)<0) { return true; } time_t t; #ifdef WIN32 SYSTEMTIME pTime; FILETIME pFTime; GetSystemTime(&pTime); SystemTimeToFileTime(&pTime, &pFTime); t = FiletimeToTimestamp(pFTime); #else time(&t); #endif LOG_DEBUG("%s is %d seconds old, redownloading at %d",filename.c_str(), (int)(t - sb.st_ctime), secs); return (t<sb.st_ctime+secs); } bool CFileSystem::fileExists(const std::string& filename) { struct stat buffer; return stat(filename.c_str(), &buffer) == 0; } bool CFileSystem::parseTorrent(const char* data, int size, IDownload* dl) { struct be_node* node=be_decoden(data, size); //#ifdef DEBUG // be_dump(node); //#endif if(node==NULL) { LOG_ERROR("couldn't parse torrent"); return false; } if (node->type!=BE_DICT) { LOG_ERROR("Error in torrent data"); be_free(node); return false; } int i; struct be_node* infonode=NULL; for (i = 0; node->val.d[i].val; ++i) { //search for a dict with name info if ((node->type==BE_DICT) && (strcmp(node->val.d[i].key,"info")==0)) { infonode=node->val.d[i].val; break; } } if (infonode==NULL) { LOG_ERROR("couldn't find info node in be dict"); be_free(node); return false; } for (i = 0; infonode->val.d[i].val; ++i) { //fetch needed data from dict and fill into dl struct be_node*datanode; datanode=infonode->val.d[i].val; switch(datanode->type) { case BE_STR: //current value is a string if ((strcmp("name",infonode->val.d[i].key)==0) && (dl->name.empty())) { //set filename if not already set dl->name=datanode->val.s; } else if (!strcmp("pieces", infonode->val.d[i].key)) { //hash sum of a piece const int count = be_str_len(datanode)/20; //one sha1 sum is 5 * 4 bytes long for (int i=0; i<count; i++) { struct IDownload::piece piece; const unsigned char* data=(unsigned char*)&datanode->val.s[i*20]; piece.sha=new HashSHA1(); if (!piece.sha->Set(data, 20)) { LOG_ERROR("Error setting sha1"); } piece.state=IDownload::STATE_NONE; dl->pieces.push_back(piece); } } break; case BE_INT: //current value is a int if (strcmp("length",infonode->val.d[i].key)==0) { //filesize dl->size=datanode->val.i; } else if (!strcmp("piece length",infonode->val.d[i].key)) { //length of a piece dl->piecesize=datanode->val.i; LOG_DEBUG("dl->piecesize: %d", dl->piecesize); } break; default: break; } } LOG_DEBUG("Parsed torrent data: %s %d", dl->name.c_str(), dl->piecesize); be_free(node); return true; } bool CFileSystem::dumpSDP(const std::string& filename) { std::list<FileData*> files; files.clear(); if (!parseSdp(filename, files)) return false; LOG_INFO("md5 (filename in pool) crc32 size filename"); std::list<FileData*>::iterator it; HashMD5 md5; for(it=files.begin(); it!=files.end(); ++it) { md5.Set((*it)->md5, sizeof((*it)->md5)); LOG_INFO("%s %.8X %8d %s",md5.toString().c_str(), (*it)->crc32, (*it)->size, (*it)->name.c_str()); } return true; }
int contact_tracker(bt_args_t *bt_args) { printf("Please wait ...\nConnecting with tracker.\n"); char *new_file; long long leng; new_file = read_file(bt_args->torrent_file, &leng); if (!new_file) return 1; char *inf = strstr(strstr(new_file, "info"), "d"); // length on ubuntu 14.04 torrent should be 44478 long long len = be_len(inf); memset(bt_args->info_hash, '\0', BT_INFO_HASH_SIZE); memset(bt_args->bt_peer_id, '\0', BT_INFO_HASH_SIZE); SHA1((unsigned char const *) inf, (size_t) len, (unsigned char *) bt_args->info_hash); char *request_to_send = malloc(FILE_NAME_MAX); request_to_send = malloc(FILE_NAME_MAX); memset(request_to_send, '\0', FILE_NAME_MAX); memcpy(bt_args->bt_peer_id, generate_peer_id(), 20); //Port number this peer is listening on. //Common behavior is for a downloader to try to listen on //port 6881 and if that port is taken try 6882, then 6883, etc. and give up after 6889. uint16_t port = INIT_PORT; bt_args->bt_info->num_pieces = bt_args->bt_info->length / bt_args->bt_info->piece_length; sprintf(request_to_send, "%s?info_hash=%s&peer_id=%s&port=%hu&uploaded=0" "&downloaded=0&left=%d&event=started&compact=1", bt_args->bt_info->announce, url_encode(bt_args->info_hash), url_encode(bt_args->bt_peer_id), port, bt_args->bt_info->length); // correct request to send on ubuntu torrent // http://torrent.ubuntu.com:6969/announce? // info_hash=%B4%15%C9%13d%3E%5F%F4%9F%E3%7D0K%BB%5En%11%ADQ%01 // announce?info_hash=%b4%15%c9%13d%3e_%f4%9f%e3%7d0K%bb%5en%11%adQ%01 // &peer_id=TueFeb32137332015RRR&port=6681&event=started&uploaded=0 // &downloaded=0&left=1162936320&compact=1 if (bt_args->verbose) printf("Request URL for tracker: %s\n", request_to_send); char *result = _send_http_request(request_to_send); if (result) { be_node *node = be_decoden(result, (long long int) be_len); if (bt_args->verbose) be_dump(node); bt_peer *peer = malloc(sizeof(bt_peer)); // parse_info(peer, node); _fill_peer_info(peer, node, 0, ""); int num_peers = 0; char *peer_num = strstr(result, "peers"); if (peer_num == NULL) { printf("Something went wrong in parsing received data!\n"); free(result); return 1; } int i = 0; peer_num += 5; char buff[20]; memset(buff, 0, 20); for (; *peer_num != ':'; peer_num++, i++) buff[i] = *peer_num; char *endptr; num_peers = (int) strtol(buff, &endptr, 10) / 6; if (num_peers == 0) { free(result); return 1; } int count = 0; pthread_t *thread = malloc(num_peers * sizeof(pthread_t)); printf("Connecting with peers.\n"); for (i = 0; i < num_peers; i++) { uint32_t ip = *(uint32_t *) (peer->peer_hashes + count); count = (int) (count + sizeof(uint32_t)); port = *(uint16_t *) (peer->peer_hashes + count); count = (int) (count + sizeof(uint16_t)); peer_t *my_peer_t = malloc(sizeof(peer_t)); my_peer_t->interested = -1; my_peer_t->choked = -1; //IP to string struct in_addr ip_addr; ip_addr.s_addr = ip; char *id = malloc(21); memset(id, 0, 21); calc_id(inet_ntoa(ip_addr), port, id); memset(my_peer_t->id, 0, ID_SIZE); strcpy((char *) my_peer_t->id, id); init_peer(my_peer_t, id, inet_ntoa(ip_addr), htons(port)); add_peer(my_peer_t, bt_args, inet_ntoa(ip_addr), port); thdata *data = malloc(sizeof(thdata)); data->th_num = i; data->bt_args = bt_args; data->bt_peer_t = my_peer_t; pthread_create (&thread[i], NULL, (void *) &_connect_function, (void *) data); } for (i = 0; i < num_peers; i++); pthread_join(thread[i], NULL); } else { printf("Something went wrong!\n"); return 1; } return 0; }
// 解码B编码的数据, 将解码后的数据放入tracker_data结构 tracker_data* get_tracker_data(char* data, int len) { tracker_data* ret; be_node* ben_res; //printf("data is %s\n",data); ben_res = be_decoden(data,len); if(ben_res->type != BE_DICT) { perror("Data not of type dict"); exit(-12); } ret = (tracker_data*)malloc(sizeof(tracker_data)); if(ret == NULL) { perror("Could not allcoate tracker_data"); exit(-12); } // 遍历键并测试它们 int i; for (i=0; ben_res->val.d[i].val != NULL; i++) { // printf("%s\n",ben_res->val.d[i].key); // 检查是否有失败键 if(!strncmp(ben_res->val.d[i].key,"failure reason",strlen("failure reason"))) { printf("Error: %s",ben_res->val.d[i].val->val.s); exit(-12); } // interval键 if(!strncmp(ben_res->val.d[i].key,"interval",strlen("interval"))) { ret->interval = (int)ben_res->val.d[i].val->val.i; } // peers键 if(!strncmp(ben_res->val.d[i].key,"peers",strlen("peers"))) { be_node* peer_list = ben_res->val.d[i].val; // printf("peer list type is %d\n",peer_list->type); // printf("peer_list name is %s\n",peer_list->val.s); // printf("peer list type is %d\n",peer_list->length); char *peer_list_start = peer_list->val.s; int len = peer_list->length; int num_of_peers = 0; while(len > 0) { num_of_peers++; len = len - 6; } if(num_of_peers == 0) { perror("接收的返回报文peer数出错"); exit(-1); } ret->numpeers = num_of_peers; // printf("num_of_peers is %d\n",num_of_peers); ret->peers = (peerdata*)malloc(num_of_peers*sizeof(peerdata)); int k; for(k=0; k<num_of_peers; k++) { //printf("loop times is %d\n",k); peerdata *temp_peer = &(ret->peers[k]); //ip int *ip_val = (int *)(peer_list->val.s); struct in_addr temp_addr; temp_addr.s_addr = *ip_val; char *ip_addr = inet_ntoa(temp_addr); temp_peer->ip = (char *)malloc(strlen(ip_addr)+1); strcpy(temp_peer->ip,ip_addr); peer_list->val.s += 4; //printf("ip is %s\n",ret->peers[k].ip); //peer id if(strcmp(ip_addr,g_my_ip) == 0) { strncpy(temp_peer->id,g_my_id,20); temp_peer->id[20] = '\0'; } else { memset(temp_peer->id,0,21*sizeof(char)); } //port unsigned short int *temp_port = (unsigned short int *)(peer_list->val.s); temp_peer->port = ntohs(*temp_port); peer_list->val.s += 2; //printf("port is %d\n",ret->peers[k].port); } peer_list->val.s = peer_list_start; //get_peers(ret,my_list); } } //printf("ben_res type is %d\n",ben_res->type); be_free(ben_res); return ret; }
// 注意: 这个函数只能处理单文件模式torrent torrentmetadata_t* parsetorrentfile(char* filename) { int i; be_node* ben_res; FILE* f; int flen; char* data; torrentmetadata_t* ret; // 打开文件, 获取数据并解码字符串 f = fopen(filename,"r"); if(f==NULL) { printf("torrent not exist!\n"); exit(-1); } flen = file_len(f); data = (char*)malloc(flen*sizeof(char)); fread((void*)data,sizeof(char),flen,f); fclose(f); ben_res = be_decoden(data,flen); // 遍历节点, 检查文件结构并填充相应的字段. if(ben_res->type != BE_DICT) { perror("Torrent file isn't a dictionary"); exit(-13); } ret = (torrentmetadata_t*)malloc(sizeof(torrentmetadata_t)); if(ret == NULL) { perror("Could not allocate torrent meta data"); exit(-13); } // 计算这个torrent的info_hash值 // 注意: SHA1函数返回的哈希值存储在一个整数数组中, 对于小端字节序主机来说, // 在与tracker或其他peer返回的哈希值进行比较时, 需要对本地存储的哈希值 // 进行字节序转换. 当你生成发送给tracker的请求时, 也需要对字节序进行转换. char* info_loc, *info_end; info_loc = strstr(data,"infod"); // 查找info键, 它的值是一个字典 if(info_loc==NULL)printf("info null\n"); info_loc += 4; // 将指针指向值开始的地方 info_end = data+flen-6; int getnode=0; while(*info_end!='\0') { if(*info_end=='n'&&*(info_end+1)=='o'&&*(info_end+2)=='d'&&*(info_end+3)=='e') { getnode=1; break; } info_end--; } if(getnode) { printf("nodes\n"); while(*info_end!='e') --info_end; } else { info_end = data+flen-1; // 去掉结尾的e if(*info_end == 'e') { --info_end; } } printf("end:%c\n",*info_end); char* p; int len = 0; for(p=info_loc; p<=info_end; p++) len++; // 计算上面字符串的SHA1哈希值以获取info_hash SHA1Context sha; SHA1Reset(&sha); SHA1Input(&sha,(const unsigned char*)info_loc,len); if(!SHA1Result(&sha)) { printf("FAILURE\n"); } memcpy(ret->info_hash,sha.Message_Digest,20); printf("SHA1:\n"); for(i=0; i<5; i++) { printf("%08X ",ret->info_hash[i]); } printf("\n"); // 检查键并提取对应的信息 int filled=0; int flag=0; for(i=0; ben_res->val.d[i].val != NULL; i++) { int j; if(!strncmp(ben_res->val.d[i].key,"announce",strlen("announce"))&&flag<1) { ret->announce = (char*)malloc(strlen(ben_res->val.d[i].val->val.s)*sizeof(char)); memcpy(ret->announce,ben_res->val.d[i].val->val.s,strlen(ben_res->val.d[i].val->val.s)); filled++; flag++; } // info是一个字典, 它还有一些其他我们关心的键 if(!strncmp(ben_res->val.d[i].key,"info",strlen("info"))) { be_dict* idict; if(ben_res->val.d[i].val->type != BE_DICT) { perror("Expected dict, got something else"); exit(-3); } idict = ben_res->val.d[i].val->val.d; // 检查这个字典的键 for(j=0; idict[j].key != NULL; j++) { if(!strncmp(idict[j].key,"length",strlen("length"))) { ret->length = idict[j].val->val.i; filled++; } if(!strncmp(idict[j].key,"name",strlen("name"))) { ret->name = (char*)malloc(strlen(idict[j].val->val.s)*sizeof(char)); memcpy(ret->name,idict[j].val->val.s,strlen(idict[j].val->val.s)); filled++; } if(!strncmp(idict[j].key,"piece length",strlen("piece length"))) { ret->piece_len = idict[j].val->val.i; filled++; } if(!strncmp(idict[j].key,"pieces",strlen("pieces"))) { int num_pieces = ret->length/ret->piece_len; if(ret->length % ret->piece_len != 0) num_pieces++; ret->pieces = (char*)malloc(num_pieces*20); memcpy(ret->pieces,idict[j].val->val.s,num_pieces*20); ret->num_pieces = num_pieces; filled++; } } // for循环结束 } // info键处理结束 } // 确认已填充了必要的字段 be_free(ben_res); if(filled < 5) { printf("Did not fill necessary field\n"); return NULL; } else return ret; }