// 解码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; }
std::string BEJSON::encode ( const std::string& key, const fmx::Data& value, const std::string& type ) { json_t * json_value; bool is_real = false; int data_type = value.GetNativeType ( ); if ( type == "null" ) { json_value = json_null ( ); } else if ( data_type == fmx::Data::kDTBoolean ) { if ( value.GetAsBoolean ( ) == true ) { json_value = json_true ( ); } else { json_value = json_false ( ); } } else if ( data_type == fmx::Data::kDTNumber || data_type == fmx::Data::kDTDate || data_type == fmx::Data::kDTTime || data_type == fmx::Data::kDTTimeStamp ) { fmx::FixPtUniquePtr number; number->AssignFixPt ( value.GetAsNumber() ); // integer or real value ? fmx::TextUniquePtr fmx_text; fmx_text->SetText ( value.GetAsText( ) ); std::string json_text = TextAsNumberString ( *fmx_text ); fmx::TextUniquePtr decimal_point; decimal_point->Assign ( "." ); bool integer = fmx_text->Find ( *decimal_point, 0 ) == fmx::Text::kSize_End; if ( integer ) { if ( json_text.empty() ) { json_text = "0"; } json_value = json_integer_with_string ( (json_int_t)number->AsFloat ( ), json_text.c_str() ); // AsLong returns an int (which overflows) } else { // put it in as string and rip out the unwanted quotes below json_value = json_string ( json_text.c_str() ); is_real = true; } } else if ( data_type == fmx::Data::kDTText ) { fmx::TextUniquePtr fmx_text; fmx_text->SetText ( value.GetAsText( ) ); std::string json_text = TextAsUTF8String ( *fmx_text ); json_value = json_string ( json_text.c_str() ); } else { // fmx::Data::kDTBinary // fmx::Data::kDTInvalid throw BEJSON_Exception ( kBE_JSON_InvalidDataTypeError ); } json_t * json = json_object ( ); int result = json_object_set ( json, key.c_str(), json_value ); if ( result ) { throw BEJSON_Exception ( result ); } size_t flags = JSON_COMPACT; char * text = json_dumps ( json, flags ); std::string out ( text ); be_free ( text ); // workaround for rounding/precision errors in reals if ( is_real ) { size_t found = out.find ( "\":\"" ); out.erase ( found + 2, 1 ); out.erase ( out.size() - 1 ); } return out; } // encode
static be_node *_be_decode(const char **data, long long *data_len) { #ifdef BE_DEBUG_DECODE fprintf(stderr, "bencode::_be_decode(pnt: %p, rem: %lld)\n", *data, *data_len); #endif be_node *ret = NULL; if (!*data_len) { #ifdef BE_DEBUG_DECODE fprintf(stderr, "bencode::_be_decode() reject invalid datalen\n"); #endif return ret; } switch (**data) { /* lists */ case 'l': { unsigned int i = 0; #ifdef BE_DEBUG_DECODE fprintf(stderr, "bencode::_be_decode() found list\n"); #endif ret = be_alloc(BE_LIST); --(*data_len); ++(*data); while (**data != 'e') { #ifdef BE_DEBUG_DECODE fprintf(stderr, "bencode::_be_decode() list get item (%d)\n", i); #endif ret->val.l = (be_node **) realloc(ret->val.l, (i + 2) * sizeof(*ret->val.l)); ret->val.l[i] = _be_decode(data, data_len); if (ret->val.l[i] == NULL) { /* failed decode - kill decode */ #ifdef BE_DEBUG_DECODE fprintf(stderr, "bencode::_be_decode() failed list decode - kill\n"); #endif be_free(ret); return NULL; } ++i; } --(*data_len); ++(*data); /* empty list case. */ if (i == 0) { ret->val.l = (be_node **) realloc(ret->val.l, 1 * sizeof(*ret->val.l)); } ret->val.l[i] = NULL; return ret; } /* dictionaries */ case 'd': { unsigned int i = 0; #ifdef BE_DEBUG_DECODE fprintf(stderr, "bencode::_be_decode() found dictionary\n"); #endif ret = be_alloc(BE_DICT); --(*data_len); ++(*data); while (**data != 'e') { #ifdef BE_DEBUG_DECODE fprintf(stderr, "bencode::_be_decode() dictionary get key (%d)\n", i); #endif ret->val.d = (be_dict *) realloc(ret->val.d, (i + 2) * sizeof(*ret->val.d)); ret->val.d[i].key = _be_decode_str(data, data_len); #ifdef BE_DEBUG_DECODE fprintf(stderr, "bencode::_be_decode() dictionary get val\n"); #endif ret->val.d[i].val = _be_decode(data, data_len); if ((ret->val.d[i].key == NULL) || (ret->val.d[i].val == NULL)) { /* failed decode - kill decode */ #ifdef BE_DEBUG_DECODE fprintf(stderr, "bencode::_be_decode() failed dict decode - kill\n"); #endif be_free(ret); return NULL; } ++i; } --(*data_len); ++(*data); /* empty dictionary case. */ if (i == 0) { ret->val.d = (be_dict *) realloc(ret->val.d, 1 * sizeof(*ret->val.d)); } ret->val.d[i].val = NULL; return ret; } /* integers */ case 'i': { ret = be_alloc(BE_INT); #ifdef BE_DEBUG_DECODE fprintf(stderr, "bencode::_be_decode() found int\n"); #endif --(*data_len); ++(*data); ret->val.i = _be_decode_int(data, data_len); if (**data != 'e') { #ifdef BE_DEBUG_DECODE fprintf(stderr, "bencode::_be_decode() reject data != e - kill\n"); #endif be_free(ret); return NULL; } --(*data_len); ++(*data); return ret; } /* byte strings */ case '0'...'9': { ret = be_alloc(BE_STR); #ifdef BE_DEBUG_DECODE fprintf(stderr, "bencode::_be_decode() found string\n"); #endif ret->val.s = _be_decode_str(data, data_len); return ret; } /* invalid */ default: #ifdef BE_DEBUG_DECODE fprintf(stderr, "bencode::_be_decode() found invalid - kill\n"); #endif return NULL; break; } return ret; }
be_node *_be_decode(const char **data, long long *data_len) { DBG("1\n"); be_node *ret = NULL; DBG("2\n"); if (!*data_len) { DBG("3\n"); return ret; } DBG("4\n"); switch (**data) { DBG("5\n"); /* lists */ case 'l': { unsigned int i = 0; DBG("%p: decoding list ...\n", *data); ret = be_alloc(BE_LIST); --(*data_len); ++(*data); while (**data != 'e') { ret->val.l = realloc(ret->val.l, (i + 2) * sizeof(*ret->val.l)); ret->val.l[i] = _be_decode(data, data_len); if (!ret->val.l[i]) break; ++i; } --(*data_len); ++(*data); /* In case of an empty list. Uncommon, but valid. */ if (!i) ret->val.l = realloc(ret->val.l, sizeof(*ret->val.l)); ret->val.l[i] = NULL; return ret; } /* dictionaries */ case 'd': { unsigned int i = 0; DBG("%p: decoding dict ...\n", *data); ret = be_alloc(BE_DICT); --(*data_len); ++(*data); while (**data != 'e') { ret->val.d = realloc(ret->val.d, (i + 2) * sizeof(*ret->val.d)); //DBG(" [%i] key: ", i); ret->val.d[i].key = _be_decode_str(data, data_len); //DBG("\n"); ret->val.d[i].val = _be_decode(data, data_len); if (!ret->val.l[i]) break; ++i; } --(*data_len); ++(*data); ret->val.d[i].val = NULL; return ret; } /* integers */ case 'i': { DBG("%p: decoding int: ", *data); ret = be_alloc(BE_INT); --(*data_len); ++(*data); ret->val.i = _be_decode_int(data, data_len); if (**data != 'e') { DBG("invalid value; rejecting it\n"); be_free(ret); return NULL; } --(*data_len); ++(*data); DBG("%lli\n", ret->val.i); return ret; } /* byte strings */ case '0'...'9': { DBG("%p: decoding byte string (%c): ", *data, **data); ret = be_alloc(BE_STR); ret->val.s = _be_decode_str(data, data_len); DBG("\n"); return ret; } /* invalid */ default: break; } return ret; }
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; }
// 解码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; }