static void on_announce_done(tr_session * session, bool did_connect, bool did_timeout, long response_code, const void * msg, size_t msglen, void * vdata) { tr_announce_response * response; struct announce_data * data = vdata; response = &data->response; (...) // lê os dados da resposta do tracker if (variant_loaded && tr_variantIsDict(&benc)) { int64_t i; size_t len; tr_variant * tmp; // variáveis ... const char * str; const uint8_t * raw; // ... temporárias if (tr_variantDictFindStr(&benc, TR_KEY_failure_reason, &str, &len)) response->errmsg = tr_strndup(str, len); if (tr_variantDictFindStr(&benc, TR_KEY_tracker_id, &str, &len)) response->tracker_id_str = tr_strndup(str, len); if (tr_variantDictFindInt(&benc, TR_KEY_complete, &i)) response->seeders = i; (...) if (tr_variantDictFindRaw(&benc, TR_KEY_peers, &raw, &len)) { response->pex = tr_peerMgrCompactToPex(raw, len, NULL, 0, &response->pex_count); } else if (tr_variantDictFindList(&benc, TR_KEY_peers, &tmp)) { response->pex = listToPex(tmp, &response->pex_count); } }
static uint64_t loadPeers(tr_variant* dict, tr_torrent* tor) { uint8_t const* str; size_t len; uint64_t ret = 0; if (tr_variantDictFindRaw(dict, TR_KEY_peers2, &str, &len)) { int const numAdded = addPeers(tor, str, len); tr_logAddTorDbg(tor, "Loaded %d IPv4 peers from resume file", numAdded); ret = TR_FR_PEERS; } if (tr_variantDictFindRaw(dict, TR_KEY_peers2_6, &str, &len)) { int const numAdded = addPeers(tor, str, len); tr_logAddTorDbg(tor, "Loaded %d IPv6 peers from resume file", numAdded); ret = TR_FR_PEERS; } return ret; }
static void on_announce_done (tr_session * session, bool did_connect, bool did_timeout, long response_code, const void * msg, size_t msglen, void * vdata) { tr_announce_response * response; struct announce_data * data = vdata; response = &data->response; response->did_connect = did_connect; response->did_timeout = did_timeout; dbgmsg (data->log_name, "Got announce response"); if (response_code != HTTP_OK) { const char * fmt = _("Tracker gave HTTP response code %1$ld (%2$s)"); const char * response_str = tr_webGetResponseStr (response_code); response->errmsg = tr_strdup_printf (fmt, response_code, response_str); } else { tr_variant benc; const bool variant_loaded = !tr_variantFromBenc (&benc, msg, msglen); if (getenv ("TR_CURL_VERBOSE") != NULL) { if (!variant_loaded) fprintf (stderr, "%s", "Announce response was not in benc format\n"); else { int i, len; char * str = tr_variantToStr (&benc, TR_VARIANT_FMT_JSON, &len); fprintf (stderr, "%s", "Announce response:\n< "); for (i=0; i<len; ++i) fputc (str[i], stderr); fputc ('\n', stderr); tr_free (str); } } if (variant_loaded && tr_variantIsDict (&benc)) { int64_t i; size_t len; tr_variant * tmp; const char * str; const uint8_t * raw; if (tr_variantDictFindStr (&benc, TR_KEY_failure_reason, &str, &len)) response->errmsg = tr_strndup (str, len); if (tr_variantDictFindStr (&benc, TR_KEY_warning_message, &str, &len)) response->warning = tr_strndup (str, len); if (tr_variantDictFindInt (&benc, TR_KEY_interval, &i)) response->interval = i; if (tr_variantDictFindInt (&benc, TR_KEY_min_interval, &i)) response->min_interval = i; if (tr_variantDictFindStr (&benc, TR_KEY_tracker_id, &str, &len)) response->tracker_id_str = tr_strndup (str, len); if (tr_variantDictFindInt (&benc, TR_KEY_complete, &i)) response->seeders = i; if (tr_variantDictFindInt (&benc, TR_KEY_incomplete, &i)) response->leechers = i; if (tr_variantDictFindInt (&benc, TR_KEY_downloaded, &i)) response->downloads = i; if (tr_variantDictFindRaw (&benc, TR_KEY_peers6, &raw, &len)) { dbgmsg (data->log_name, "got a peers6 length of %zu", len); response->pex6 = tr_peerMgrCompact6ToPex (raw, len, NULL, 0, &response->pex6_count); } if (tr_variantDictFindRaw (&benc, TR_KEY_peers, &raw, &len)) { dbgmsg (data->log_name, "got a compact peers length of %zu", len); response->pex = tr_peerMgrCompactToPex (raw, len, NULL, 0, &response->pex_count); } else if (tr_variantDictFindList (&benc, TR_KEY_peers, &tmp)) { response->pex = listToPex (tmp, &response->pex_count); dbgmsg (data->log_name, "got a peers list with %zu entries", response->pex_count); } } if (variant_loaded) tr_variantFree (&benc); } tr_runInEventThread (session, on_announce_done_eventthread, data); }
static uint64_t loadProgress(tr_variant* dict, tr_torrent* tor) { uint64_t ret = 0; tr_variant* prog; tr_info const* inf = tr_torrentInfo(tor); for (size_t i = 0; i < inf->pieceCount; ++i) { inf->pieces[i].timeChecked = 0; } if (tr_variantDictFindDict(dict, TR_KEY_progress, &prog)) { char const* err; char const* str; uint8_t const* raw; size_t rawlen; tr_variant* l; tr_variant* b; struct tr_bitfield blocks = TR_BITFIELD_INIT; if (tr_variantDictFindList(prog, TR_KEY_time_checked, &l)) { /* per-piece timestamps were added in 2.20. If some of a file's pieces have been checked more recently than the file's mtime, and some lest recently, then that file will have a list containing timestamps for each piece. However, the most common use case is that the file doesn't change after it's downloaded. To reduce overhead in the .resume file, only a single timestamp is saved for the file if *all* or *none* of the pieces were tested more recently than the file's mtime. */ for (tr_file_index_t fi = 0; fi < inf->fileCount; ++fi) { tr_variant* b = tr_variantListChild(l, fi); tr_file const* f = &inf->files[fi]; if (tr_variantIsInt(b)) { int64_t t; tr_variantGetInt(b, &t); for (tr_piece_index_t i = f->firstPiece; i <= f->lastPiece; ++i) { inf->pieces[i].timeChecked = (time_t)t; } } else if (tr_variantIsList(b)) { int64_t offset = 0; int const pieces = f->lastPiece + 1 - f->firstPiece; tr_variantGetInt(tr_variantListChild(b, 0), &offset); for (int i = 0; i < pieces; ++i) { int64_t t = 0; tr_variantGetInt(tr_variantListChild(b, i + 1), &t); inf->pieces[f->firstPiece + i].timeChecked = (time_t)(t != 0 ? t + offset : 0); } } } } else if (tr_variantDictFindList(prog, TR_KEY_mtimes, &l)) { /* Before 2.20, we stored the files' mtimes in the .resume file. When loading the .resume file, a torrent's file would be flagged as untested if its stored mtime didn't match its real mtime. */ for (tr_file_index_t fi = 0; fi < inf->fileCount; ++fi) { int64_t t; if (tr_variantGetInt(tr_variantListChild(l, fi), &t)) { tr_file const* f = &inf->files[fi]; time_t const mtime = tr_torrentGetFileMTime(tor, fi); time_t const timeChecked = mtime == t ? mtime : 0; for (tr_piece_index_t i = f->firstPiece; i <= f->lastPiece; ++i) { inf->pieces[i].timeChecked = timeChecked; } } } } err = NULL; tr_bitfieldConstruct(&blocks, tor->blockCount); if ((b = tr_variantDictFind(prog, TR_KEY_blocks)) != NULL) { size_t buflen; uint8_t const* buf; if (!tr_variantGetRaw(b, &buf, &buflen)) { err = "Invalid value for \"blocks\""; } else if (buflen == 3 && memcmp(buf, "all", 3) == 0) { tr_bitfieldSetHasAll(&blocks); } else if (buflen == 4 && memcmp(buf, "none", 4) == 0) { tr_bitfieldSetHasNone(&blocks); } else { tr_bitfieldSetRaw(&blocks, buf, buflen, true); } } else if (tr_variantDictFindStr(prog, TR_KEY_have, &str, NULL)) { if (strcmp(str, "all") == 0) { tr_bitfieldSetHasAll(&blocks); } else { err = "Invalid value for HAVE"; } } else if (tr_variantDictFindRaw(prog, TR_KEY_bitfield, &raw, &rawlen)) { tr_bitfieldSetRaw(&blocks, raw, rawlen, true); } else { err = "Couldn't find 'pieces' or 'have' or 'bitfield'"; } if (err != NULL) { tr_logAddTorDbg(tor, "Torrent needs to be verified - %s", err); } else { tr_cpBlockInit(&tor->completion, &blocks); } tr_bitfieldDestruct(&blocks); ret = TR_FR_PROGRESS; } return ret; }
int tr_dhtInit (tr_session *ss) { tr_variant benc; int rc; bool have_id = false; char * dat_file; uint8_t * nodes = NULL, * nodes6 = NULL; const uint8_t * raw; size_t len, len6; struct bootstrap_closure * cl; if (session) /* already initialized */ return -1; tr_logAddNamedDbg ("DHT", "Initializing DHT"); if (tr_env_key_exists ("TR_DHT_VERBOSE")) dht_debug = stderr; dat_file = tr_buildPath (ss->configDir, "dht.dat", NULL); rc = tr_variantFromFile (&benc, TR_VARIANT_FMT_BENC, dat_file, NULL) ? 0 : -1; tr_free (dat_file); if (rc == 0) { have_id = tr_variantDictFindRaw (&benc, TR_KEY_id, &raw, &len); if (have_id && len==20) memcpy (myid, raw, len); if (ss->udp_socket != TR_BAD_SOCKET && tr_variantDictFindRaw (&benc, TR_KEY_nodes, &raw, &len) && ! (len%6)) { nodes = tr_memdup (raw, len); } if (ss->udp6_socket != TR_BAD_SOCKET && tr_variantDictFindRaw (&benc, TR_KEY_nodes6, &raw, &len6) && ! (len6%18)) { nodes6 = tr_memdup (raw, len6); } tr_variantFree (&benc); } if (nodes == NULL) len = 0; if (nodes6 == NULL) len6 = 0; if (have_id) tr_logAddNamedInfo ("DHT", "Reusing old id"); else { /* Note that DHT ids need to be distributed uniformly, * so it should be something truly random. */ tr_logAddNamedInfo ("DHT", "Generating new id"); tr_rand_buffer (myid, 20); } rc = dht_init (ss->udp_socket, ss->udp6_socket, myid, NULL); if (rc < 0) goto fail; session = ss; cl = tr_new (struct bootstrap_closure, 1); cl->session = session; cl->nodes = nodes; cl->nodes6 = nodes6; cl->len = len; cl->len6 = len6; tr_threadNew (dht_bootstrap, cl); dht_timer = evtimer_new (session->event_base, timer_callback, session); tr_timerAdd (dht_timer, 0, tr_rand_int_weak (1000000)); tr_logAddNamedDbg ("DHT", "DHT initialized"); return 1; fail: tr_logAddNamedDbg ("DHT", "DHT initialization failed (errno = %d)", errno); session = NULL; return -1; }