static void on_scrape_done (tr_session * session, bool did_connect, bool did_timeout, long response_code, const void * msg, size_t msglen, void * vdata) { tr_scrape_response * response; struct scrape_data * data = vdata; response = &data->response; response->did_connect = did_connect; response->did_timeout = did_timeout; dbgmsg (data->log_name, "Got scrape response for \"%s\"", response->url); 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 top; int64_t intVal; tr_variant * files; tr_variant * flags; size_t len; const char * str; const bool variant_loaded = !tr_variantFromBenc (&top, msg, msglen); if (getenv ("TR_CURL_VERBOSE") != NULL) { if (!variant_loaded) fprintf (stderr, "%s", "Scrape response was not in benc format\n"); else { int i, len; char * str = tr_variantToStr (&top, TR_VARIANT_FMT_JSON, &len); fprintf (stderr, "%s", "Scrape response:\n< "); for (i=0; i<len; ++i) fputc (str[i], stderr); fputc ('\n', stderr); tr_free (str); } } if (variant_loaded) { if (tr_variantDictFindStr (&top, TR_KEY_failure_reason, &str, &len)) response->errmsg = tr_strndup (str, len); if (tr_variantDictFindDict (&top, TR_KEY_flags, &flags)) if (tr_variantDictFindInt (flags, TR_KEY_min_request_interval, &intVal)) response->min_request_interval = intVal; if (tr_variantDictFindDict (&top, TR_KEY_files, &files)) { int i = 0; for (;;) { int j; tr_quark key; tr_variant * val; /* get the next "file" */ if (!tr_variantDictChild (files, i++, &key, &val)) break; /* populate the corresponding row in our response array */ for (j=0; j<response->row_count; ++j) { struct tr_scrape_response_row * row = &response->rows[j]; if (!memcmp (tr_quark_get_string(key,NULL), row->info_hash, SHA_DIGEST_LENGTH)) { if (tr_variantDictFindInt (val, TR_KEY_complete, &intVal)) row->seeders = intVal; if (tr_variantDictFindInt (val, TR_KEY_incomplete, &intVal)) row->leechers = intVal; if (tr_variantDictFindInt (val, TR_KEY_downloaded, &intVal)) row->downloads = intVal; if (tr_variantDictFindInt (val, TR_KEY_downloaders, &intVal)) row->downloaders = intVal; break; } } } } tr_variantFree (&top); } } tr_runInEventThread (session, on_scrape_done_eventthread, data); }
static void doScrape (const tr_info * inf) { unsigned int i; for (i=0; i<inf->trackerCount; ++i) { CURL * curl; CURLcode res; struct evbuffer * buf; const char * scrape = inf->trackers[i].scrape; char * url; char escaped[SHA_DIGEST_LENGTH*3 + 1]; if (scrape == NULL) continue; tr_http_escape_sha1 (escaped, inf->hash); url = tr_strdup_printf ("%s%cinfo_hash=%s", scrape, strchr (scrape, '?') ? '&' : '?', escaped); printf ("%s ... ", url); fflush (stdout); buf = evbuffer_new (); curl = tr_curl_easy_init (buf); curl_easy_setopt (curl, CURLOPT_URL, url); curl_easy_setopt (curl, CURLOPT_TIMEOUT, TIMEOUT_SECS); if ((res = curl_easy_perform (curl))) { printf ("error: %s\n", curl_easy_strerror (res)); } else { long response; curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &response); if (response != 200) { printf ("error: unexpected response %ld \"%s\"\n", response, tr_webGetResponseStr (response)); } else /* HTTP OK */ { tr_variant top; tr_variant * files; bool matched = false; const char * begin = (const char*) evbuffer_pullup (buf, -1); if (!tr_variantFromBenc (&top, begin, evbuffer_get_length(buf))) { if (tr_variantDictFindDict (&top, TR_KEY_files, &files)) { int i = 0; tr_quark key; tr_variant * val; while (tr_variantDictChild (files, i++, &key, &val)) { if (memcmp (inf->hash, tr_quark_get_string (key, NULL), SHA_DIGEST_LENGTH) == 0) { int64_t seeders = -1; int64_t leechers = -1; tr_variantDictFindInt (val, TR_KEY_complete, &seeders); tr_variantDictFindInt (val, TR_KEY_incomplete, &leechers); printf ("%d seeders, %d leechers\n", (int)seeders, (int)leechers); matched = true; } } } tr_variantFree (&top); } if (!matched) printf ("no match\n"); } } curl_easy_cleanup (curl); evbuffer_free (buf); tr_free (url); } }