size_t decode_dict(const char *b,size_t len,const char *keylist) { size_t rl,dl,nl; const char *pkey; dl = 0; if(2 > len || *b != 'd') return 0; dl++; len--; for(;len && *(b + dl) != 'e';){ rl = buf_str(b + dl,len,&pkey,&nl); if( !rl || KEYNAME_SIZ < nl) return 0; dl += rl; len -= rl; if(keylist && compare_key(pkey,nl,keylist) == 0){ pkey = next_key(keylist); if(! *pkey ) return dl; rl = decode_dict(b + dl,len, pkey); if( !rl ) return 0; return dl + rl; } rl = decode_rev(b + dl,len,(const char*) 0); if( !rl ) return 0; dl += rl;len -= rl; } if( !len || keylist) return 0; return dl + 1; /* add the last char 'e' */ }
size_t decode_rev(const char *b,size_t len,const char *keylist) { if( !b ) return 0; switch( *b ){ case 'i': return decode_int(b,len); case 'd': return decode_dict(b,len,keylist); case 'l': return decode_list(b,len,keylist); default: return decode_str(b,len); } }
/* Determine the type and pass processing to the next apropriate function * Accepts: buffer, pointer to msg, char of type return, pointer to memory registrar * Returns: a pointer to the decoded msg */ void *decode_next(struct Buffer *buf, char **bi, char *type) { if (*bi < buf->cnt + (buf->size - 2)) { switch (**bi) { case 'd': *type = 'd'; return decode_dict(buf, bi); break; case 'l': *type = 'l'; return decode_list(buf, bi); break; case 'i': *type = 'i'; return decode_int(buf, bi); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': *type = 's'; return decode_str(buf, bi); break; default: fprintf(stderr, "error: decode_next could not determine type encoding %c\n", **bi); exit(1); } } else { return NULL; //fprintf(stderr, "error: decode_next - unexcpected end of buffer\n"); //exit(1); } }
int btTracker::_UpdatePeerList(char *buf, size_t bufsiz) { char tmphost[MAXHOSTNAMELEN + 1] = {'\0'}; char warnmsg[1024] = {'\0'}; char failreason[1024] = {'\0'}; const char *ps = NULL; size_t i, pos, tmpport; size_t cnt = 0; struct sockaddr_in addr = {0, 0, {0}, {0}}; memset((void *) &addr, 0, sizeof(addr)); if (decode_query(buf, bufsiz, "failure reason", &ps, &i, (int64_t *) 0, QUERY_STR)) { if (i < 1024) { memcpy(failreason, ps, i); failreason[i] = '\0'; } else { memcpy(failreason, ps, 1000); failreason[1000] = '\0'; strcat(failreason, "..."); } CONSOLE.Warning(1, "TRACKER FAILURE REASON: %s", failreason); return -1; } if (decode_query (buf, bufsiz, "warning message", &ps, &i, (int64_t *) 0, QUERY_STR)) { if (i < 1024) { memcpy(warnmsg, ps, i); warnmsg[i] = '\0'; } else { memcpy(warnmsg, ps, 1000); warnmsg[1000] = '\0'; strcat(warnmsg, "..."); } CONSOLE.Warning(2, "TRACKER WARNING: %s", warnmsg); } m_peers_count = m_seeds_count = 0; if (decode_query (buf, bufsiz, "tracker id", &ps, &i, (int64_t *) 0, QUERY_STR)) { if (i <= PEER_ID_LEN) { memcpy(m_trackerid, ps, i); m_trackerid[i] = '\0'; } else { memcpy(m_trackerid, ps, PEER_ID_LEN); m_trackerid[PEER_ID_LEN] = '\0'; } } if (!decode_query(buf, bufsiz, "interval", (const char **) 0, &i, (int64_t *) 0, QUERY_INT)) return -1; if (m_interval != (time_t) i) m_interval = (time_t) i; if (m_default_interval != (time_t) i) m_default_interval = (time_t) i; if (decode_query(buf, bufsiz, "complete", (const char **) 0, &i, (int64_t *) 0, QUERY_INT)) m_seeds_count = i; if (decode_query(buf, bufsiz, "incomplete", (const char **) 0, &i, (int64_t *) 0, QUERY_INT)) m_peers_count = m_seeds_count + i; else { if (arg_verbose && 0 == m_seeds_count) CONSOLE.Debug("Tracker did not supply peers count."); m_peers_count = m_seeds_count; } pos = decode_query(buf, bufsiz, "peers", (const char **) 0, (size_t *) 0, (int64_t *) 0, QUERY_POS); if (!pos) { return -1; } if (4 > bufsiz - pos) { return -1; } // peers list ̫С buf += (pos + 1); bufsiz -= (pos + 1); ps = buf - 1; if (*ps != 'l') { // binary peers section if not 'l' addr.sin_family = AF_INET; i = 0; while (*ps != ':') i = i * 10 + (*ps++ -'0'); i /= 6; ps++; while (i-- > 0) { memcpy(&addr.sin_addr, ps, sizeof(struct in_addr)); memcpy(&addr.sin_port, ps + sizeof(struct in_addr), sizeof(unsigned short)); if (!Self.IpEquiv(addr)) { cnt++; IPQUEUE.Add(&addr); } ps += 6; } } else for (; bufsiz && *buf != 'e'; buf += pos, bufsiz -= pos) { pos = decode_dict(buf, bufsiz, (char *) 0); if (!pos) break; if (!decode_query (buf, pos, "ip", &ps, &i, (int64_t *) 0, QUERY_STR) || MAXHOSTNAMELEN < i) continue; memcpy(tmphost, ps, i); tmphost[i] = '\0'; if (!decode_query (buf, pos, "port", (const char **) 0, &tmpport, (int64_t *) 0, QUERY_INT)) continue; if (!decode_query (buf, pos, "peer id", &ps, &i, (int64_t *) 0, QUERY_STR) && i != 20) continue; if (_IPsin(tmphost, tmpport, &addr) < 0) { CONSOLE.Warning(3, "warn, detected invalid ip address %s.", tmphost); continue; } if (!Self.IpEquiv(addr)) { cnt++; IPQUEUE.Add(&addr); } } if (0 == m_peers_count) { m_peers_count = cnt + 1; // include myself m_f_boguspeercnt = 1; } else m_f_boguspeercnt = 0; if (arg_verbose) CONSOLE.Debug("new peers=%d; next check in %d sec", (int) cnt, (int) m_interval); return 0; }
int btContent::InitialFromMI(const char *metainfo_fname,const char *saveas) { #define ERR_RETURN() {if(b) delete []b; return -1;} unsigned char *ptr = m_shake_buffer; char *b; const char *s; size_t flen, q, r; b = _file2mem(metainfo_fname,&flen); if ( !b ) return -1; // announce if( !meta_str("announce",&s,&r) ) ERR_RETURN(); if( r > MAXPATHLEN ) ERR_RETURN(); m_announce = new char [r + 1]; memcpy(m_announce, s, r); m_announce[r] = '\0'; // infohash if( !(r = meta_pos("info")) ) ERR_RETURN(); if( !(q = decode_dict(b + r, flen - r, (char *) 0)) ) ERR_RETURN(); Sha1(b + r, q, m_shake_buffer + 28); if( meta_int("creation date",&r)) m_create_date = (time_t) r; // hash table if( !meta_str("info|pieces",&s,&m_hashtable_length) || m_hashtable_length % 20 != 0) ERR_RETURN(); m_hash_table = new unsigned char[m_hashtable_length]; #ifndef WINDOWS if( !m_hash_table ) ERR_RETURN(); #endif memcpy(m_hash_table, s, m_hashtable_length); if(!meta_int("info|piece length",&m_piece_length)) ERR_RETURN(); m_npieces = m_hashtable_length / 20; if( m_piece_length > cfg_max_slice_size * cfg_req_queue_length ){ fprintf(stderr,"error, piece length too long[%u]. please recomplie CTorrent with a larger cfg_max_slice_size in <btconfig.h>.\n", m_piece_length); ERR_RETURN(); } if( m_piece_length < cfg_req_slice_size ) cfg_req_slice_size = m_piece_length; else{ for( ;(m_piece_length / cfg_req_slice_size) >= cfg_req_queue_length; ){ cfg_req_slice_size *= 2; if( cfg_req_slice_size > cfg_max_slice_size ) ERR_RETURN(); } } if( m_btfiles.BuildFromMI(b, flen, saveas) < 0) ERR_RETURN(); delete []b; PrintOut(); if( arg_flg_exam_only ) return 0; if( ( r = m_btfiles.CreateFiles() ) < 0) ERR_RETURN(); global_piece_buffer = new char[m_piece_length]; #ifndef WINDOWS if( !global_piece_buffer ) ERR_RETURN(); #endif pBF = new BitField(m_npieces); #ifndef WINDOWS if( !pBF ) ERR_RETURN(); #endif m_left_bytes = m_btfiles.GetTotalLength() / m_piece_length; if( m_btfiles.GetTotalLength() % m_piece_length ) m_left_bytes++; if( m_left_bytes != m_npieces ) ERR_RETURN(); m_left_bytes = m_btfiles.GetTotalLength(); if( arg_bitfield_file ){ if( !arg_flg_check_only ){ if( pBF->SetReferFile(arg_bitfield_file) >= 0){ size_t idx; r = 0; for( idx = 0; idx < m_npieces; idx++ ) if( pBF->IsSet(idx) ) m_left_bytes -= GetPieceLength(idx); } else{ fprintf(stderr,"warn, couldn't set bit field refer file %s.\n",arg_bitfield_file); } } if( r ) CheckExist(); }else if( arg_flg_force_seed_mode ){ pBF->SetAll(); m_left_bytes = 0; }else if( r ){ CheckExist(); } printf("Already/Total: %u/%u\n",pBF->Count(),m_npieces); if( arg_flg_check_only ){ if( arg_bitfield_file ) pBF->WriteToFile(arg_bitfield_file); exit(1); } CacheConfigure(); *ptr = (unsigned char) 19; ptr++; // protocol string length memcpy(ptr,"BitTorrent protocol",19); ptr += 19; // protocol string memset(ptr,0,8); // reserved set zero. { // peer id int i; ptr = m_shake_buffer + 48; for( i = 0; i < 20; i++,ptr++) *ptr = (unsigned char)(rand() & 0xFF); } return 0; }
int btFiles::BuildFromMI(const char *metabuf, const size_t metabuf_len, const char *saveas) { char path[MAXPATHLEN]; const char *s, *p; size_t r,q,n; int64_t t; int f_warned = 0; if( !decode_query(metabuf, metabuf_len, "info|name", &s, &q, (int64_t*)0, QUERY_STR) || MAXPATHLEN <= q ) return -1; memcpy(path, s, q); path[q] = '\0'; r = decode_query(metabuf, metabuf_len, "info|files", (const char**)0, &q, (int64_t*)0, QUERY_POS); if( r ){ BTFILE *pbf_last = (BTFILE*) 0; BTFILE *pbf = (BTFILE*) 0; size_t dl; if( decode_query(metabuf,metabuf_len,"info|length", (const char**) 0,(size_t*) 0,(int64_t*) 0,QUERY_LONG) ) return -1; if( saveas ){ m_directory = new char[strlen(saveas) + 1]; #ifndef WINDOWS if(!m_directory) return -1; #endif strcpy(m_directory,saveas); }else{ int f_conv; char *tmpfn = new char[strlen(path)*2+5]; #ifndef WINDOWS if( !tmpfn ) return -1; #endif if( f_conv = ConvertFilename(tmpfn, path, strlen(path)*2+5) ){ if( arg_flg_convert_filenames ){ m_directory = new char[strlen(tmpfn) + 1]; #ifndef WINDOWS if( !m_directory ){ delete []tmpfn; return -1; } #endif strcpy(m_directory,tmpfn); }else{ CONSOLE.Warning(3, "Dir name contains non-printable characters; use -T to convert."); f_warned = 1; } } delete []tmpfn; if( !f_conv || !arg_flg_convert_filenames ){ m_directory = new char[strlen(path) + 1]; #ifndef WINDOWS if( !m_directory ) return -1; #endif strcpy(m_directory,path); } } /* now r saved the pos of files list. q saved list length */ p = metabuf + r + 1; q--; for(; q && 'e' != *p; p += dl, q -= dl){ if(!(dl = decode_dict(p, q, (const char*) 0)) ) return -1; if( !decode_query(p, dl, "length", (const char**) 0, (size_t*) 0,&t,QUERY_LONG) ) return -1; pbf = _new_bfnode(); #ifndef WINDOWS if( !pbf ) return -1; #endif pbf->bf_length = t; m_total_files_length += t; r = decode_query(p, dl, "path", (const char **)0, &n, (int64_t*)0, QUERY_POS); if( !r ) return -1; if(!decode_list2path(p + r, n, path)) return -1; int f_conv; char *tmpfn = new char[strlen(path)*2+5]; #ifndef WINDOWS if( !tmpfn ) return -1; #endif if( f_conv = ConvertFilename(tmpfn, path, strlen(path)*2+5) ){ if( arg_flg_convert_filenames ){ pbf->bf_filename = new char[strlen(tmpfn) + 1]; #ifndef WINDOWS if( !pbf->bf_filename ){ delete []tmpfn; return -1; } #endif strcpy(pbf->bf_filename, tmpfn); }else if(!f_warned){ CONSOLE.Warning(3, "Filename contains non-printable characters; use -T to convert."); f_warned = 1; } } delete []tmpfn; if( !f_conv || !arg_flg_convert_filenames ){ pbf->bf_filename = new char[strlen(path) + 1]; #ifndef WINDOWS if( !pbf->bf_filename ) return -1; #endif strcpy(pbf->bf_filename, path); } if(pbf_last) pbf_last->bf_next = pbf; else m_btfhead = pbf; pbf_last = pbf; } }else{ if( !decode_query(metabuf,metabuf_len,"info|length", (const char**) 0,(size_t*) 0,&t,QUERY_LONG) ) return -1; m_btfhead = _new_bfnode(); #ifndef WINDOWS if( !m_btfhead) return -1; #endif m_btfhead->bf_length = m_total_files_length = t; if( saveas ){ m_btfhead->bf_filename = new char[strlen(saveas) + 1]; #ifndef WINDOWS if(!m_btfhead->bf_filename ) return -1; #endif strcpy(m_btfhead->bf_filename, saveas); }else if( arg_flg_convert_filenames ){ char *tmpfn = new char[strlen(path)*2+5]; #ifndef WINDOWS if( !tmpfn ) return -1; #endif ConvertFilename(tmpfn, path, strlen(path)*2+5); m_btfhead->bf_filename = new char[strlen(tmpfn) + 1]; #ifndef WINDOWS if( !m_btfhead->bf_filename ){ delete []tmpfn; return -1; } #endif strcpy(m_btfhead->bf_filename, tmpfn); delete []tmpfn; }else{ m_btfhead->bf_filename = new char[strlen(path) + 1]; #ifndef WINDOWS if(!m_btfhead->bf_filename ) return -1; #endif strcpy(m_btfhead->bf_filename, path); } } return 0; }
dt_result_t btTracker::ParseResponse(const char *buf, size_t bufsiz) { char tmphost[MAXHOSTNAMELEN]; const char *ps; size_t i, pos, tmpport; int64_t bint; dt_count_t cnt = 0; struct sockaddr_in addr; if( decode_query(buf, bufsiz, "failure reason", &ps, &i, (int64_t *)0, DT_QUERY_STR) ){ char failreason[1024]; if( i < 1024 ){ memcpy(failreason, ps, i); failreason[i] = '\0'; }else{ memcpy(failreason, ps, 1000); failreason[1000] = '\0'; strcat(failreason, "..."); } CONSOLE.Warning(1, "TRACKER FAILURE from %s: %s", m_spec->url, failreason); return DT_FAILURE; } if( decode_query(buf, bufsiz, "warning message", &ps, &i, (int64_t *)0, DT_QUERY_STR) ){ char warnmsg[1024]; if( i < 1024 ){ memcpy(warnmsg, ps, i); warnmsg[i] = '\0'; }else{ memcpy(warnmsg, ps, 1000); warnmsg[1000] = '\0'; strcat(warnmsg, "..."); } CONSOLE.Warning(2, "TRACKER WARNING from %s: %s", m_spec->url, warnmsg); } m_peers_count = m_seeds_count = 0; if( decode_query(buf, bufsiz, "tracker id", &ps, &i, (int64_t *)0, DT_QUERY_STR) ){ if( i <= PEER_ID_LEN ){ memcpy(m_trackerid, ps, i); m_trackerid[i] = '\0'; }else{ memcpy(m_trackerid, ps, PEER_ID_LEN); m_trackerid[PEER_ID_LEN] = '\0'; } } if( decode_query(buf, bufsiz, "interval", (const char **)0, NULL, &bint, DT_QUERY_INT) ){ m_interval = m_default_interval = (time_t)bint; }else{ CONSOLE.Debug("Tracker at %s did not specify interval.", m_spec->url); m_interval = m_default_interval; } if( decode_query(buf, bufsiz, "complete", (const char **)0, NULL, &bint, DT_QUERY_INT) ){ m_seeds_count = bint; } if( decode_query(buf, bufsiz, "incomplete", (const char **)0, NULL, &bint, DT_QUERY_INT) ){ m_peers_count = m_seeds_count + bint; }else{ if( *cfg_verbose && 0==m_seeds_count ) CONSOLE.Debug("Tracker at %s did not supply peers count.", m_spec->url); m_peers_count = m_seeds_count; } pos = decode_query(buf, bufsiz, "peers", (const char **)0, (size_t *)0, (int64_t *)0, DT_QUERY_POS); if( !pos ){ CONSOLE.Debug("Tracker at %s did not supply peers.", m_spec->url); return DT_FAILURE; } if( 4 > bufsiz - pos ){ CONSOLE.Debug("Tracker at %s supplied an invalid peers list.", m_spec->url); return DT_FAILURE; } buf += (pos + 1); bufsiz -= (pos + 1); ps = buf-1; if( *ps != 'l' ){ // binary peers section if not 'l' addr.sin_family = AF_INET; i = 0; while( *ps != ':' ) i = i * 10 + (*ps++ - '0'); i /= 6; ps++; while( i-- > 0 ){ memcpy(&addr.sin_addr, ps, sizeof(struct in_addr)); memcpy(&addr.sin_port, ps+sizeof(struct in_addr), sizeof(unsigned short)); if( !Self.IpEquiv(addr) ){ cnt++; IPQUEUE.Add(&addr); } ps += 6; } }else for( ; bufsiz && *buf != 'e'; buf += pos, bufsiz -= pos ){ pos = decode_dict(buf, bufsiz, (char *)0); if( !pos ) break; if( !decode_query(buf, pos, "ip", &ps, &i, (int64_t *)0, DT_QUERY_STR) || MAXHOSTNAMELEN < i ){ continue; } memcpy(tmphost, ps, i); tmphost[i] = '\0'; if( !decode_query(buf, pos, "port", (const char **)0, NULL, &bint, DT_QUERY_INT) ){ continue; } tmpport = bint; if( !decode_query(buf, pos, "peer id", &ps, &i, (int64_t *)0, DT_QUERY_STR) && i != 20 ){ continue; } if( _IPsin(tmphost, tmpport, &addr) < 0 ){ CONSOLE.Warning(3, "warn, detected invalid ip address %s.", tmphost); continue; } if( !Self.IpEquiv(addr) ){ cnt++; IPQUEUE.Add(&addr); } } if( 0==m_peers_count ){ m_peers_count = cnt + 1; // include myself m_f_boguspeercnt = 1; }else m_f_boguspeercnt = 0; if(*cfg_verbose) CONSOLE.Debug("new peers=%d; next check in %d sec [%s]", (int)cnt, (int)m_interval, m_spec->url); return DT_SUCCESS; }
int btFiles::BuildFromMI(const char *metabuf, const size_t metabuf_len, const char *saveas) { char path[MAXPATHLEN]; const char *s, *p; size_t r,q,n; if( !decode_query(metabuf, metabuf_len, "info|name",&s,&q,QUERY_STR) || MAXPATHLEN <= q) return -1; memcpy(path, s, q); path[q] = '\0'; r = decode_query(metabuf,metabuf_len,"info|files",(const char**) 0, &q,QUERY_POS); if( r ){ BTFILE *pbf_last = (BTFILE*) 0; BTFILE *pbf = (BTFILE*) 0; size_t dl; if( decode_query(metabuf,metabuf_len,"info|length", (const char**) 0,(size_t*) 0,QUERY_INT) ) return -1; if( saveas ){ m_directory = new char[strlen(saveas) + 1]; #ifndef WINDOWS if(!m_directory) return -1; #endif strcpy(m_directory,saveas); }else{ m_directory = new char[strlen(path) + 1]; #ifndef WINDOWS if( !m_directory) return -1; #endif strcpy(m_directory,path); } /* now r saved the pos of files list. q saved list length */ p = metabuf + r + 1; q--; for(; q && 'e' != *p; p += dl, q -= dl){ if(!(dl = decode_dict(p, q, (const char*) 0)) ) return -1; if( !decode_query(p, dl, "length", (const char**) 0, &r,QUERY_INT) ) return -1; pbf = _new_bfnode(); #ifndef WINDOWS if( !pbf ) return -1; #endif pbf->bf_length = r; m_total_files_length += r; r = decode_query(p, dl, "path", (const char **) 0, &n,QUERY_POS); if( !r ) return -1; if(!decode_list2path(p + r, n, path)) return -1; pbf->bf_filename = new char[strlen(path) + 1]; #ifndef WINDOWS if( !pbf->bf_filename ) return -1; #endif strcpy(pbf->bf_filename, path); if(pbf_last) pbf_last->bf_next = pbf; else m_btfhead = pbf; pbf_last = pbf; } }else{ if( !decode_query(metabuf,metabuf_len,"info|length", (const char**) 0,(size_t*) &q,QUERY_INT) ) return -1; m_btfhead = _new_bfnode(); #ifndef WINDOWS if( !m_btfhead) return -1; #endif m_btfhead->bf_length = m_total_files_length = q; if( saveas ){ m_btfhead->bf_filename = new char[strlen(saveas) + 1]; #ifndef WINDOWS if(!m_btfhead->bf_filename ) return -1; #endif strcpy(m_btfhead->bf_filename, saveas); }else{ m_btfhead->bf_filename = new char[strlen(path) + 1]; #ifndef WINDOWS if(!m_btfhead->bf_filename ) return -1; #endif strcpy(m_btfhead->bf_filename, path); } } return 0; }