static char* getOldTorrentFilename( const tr_session * session, const tr_info * inf ) { int i; char * path; struct stat sb; const int tagCount = 5; const char * tags[] = { "beos", "cli", "daemon", "macosx", "wx" }; /* test the beos, cli, daemon, macosx, wx tags */ for( i=0; i<tagCount; ++i ) { path = tr_strdup_printf( "%s%c%s-%s", tr_getTorrentDir( session ), '/', inf->hashString, tags[i] ); if( !stat( path, &sb ) && ( ( sb.st_mode & S_IFMT ) == S_IFREG ) ) return path; tr_free( path ); } /* test a non-tagged file */ path = tr_buildPath( tr_getTorrentDir( session ), inf->hashString, NULL ); if( !stat( path, &sb ) && ( ( sb.st_mode & S_IFMT ) == S_IFREG ) ) return path; tr_free( path ); /* return the -gtk form by default, since that's the most common case. don't bother testing stat() on it since this is the last candidate and we don't want to return NULL anyway */ return tr_strdup_printf( "%s%c%s-%s", tr_getTorrentDir( session ), '/', inf->hashString, "gtk" ); }
static char* getResumeFilename(tr_torrent const* tor) { char* base = tr_metainfoGetBasename(tr_torrentInfo(tor)); char* filename = tr_strdup_printf("%s" TR_PATH_DELIMITER_STR "%s.resume", tr_getResumeDir(tor->session), base); tr_free(base); return filename; }
static void requestNextChunk( tr_webseed * w ) { tr_torrent * tor = tr_torrentFindFromHash( w->session, w->hash ); if( tor != NULL ) { const tr_info * inf = tr_torrentInfo( tor ); const uint32_t have = EVBUFFER_LENGTH( w->content ); const uint32_t left = w->byteCount - have; const uint32_t pieceOffset = w->pieceOffset + have; tr_file_index_t fileIndex; uint64_t fileOffset; uint32_t thisPass; char * url; char * range; tr_ioFindFileLocation( tor, w->pieceIndex, pieceOffset, &fileIndex, &fileOffset ); thisPass = MIN( left, inf->files[fileIndex].length - fileOffset ); url = makeURL( w, &inf->files[fileIndex] ); /*fprintf( stderr, "url is [%s]\n", url );*/ range = tr_strdup_printf( "%"PRIu64"-%"PRIu64, fileOffset, fileOffset + thisPass - 1 ); /*fprintf( stderr, "range is [%s] ... we want %lu total, we have %lu, so %lu are left, and we're asking for %lu this time\n", range, (unsigned long)w->byteCount, (unsigned long)have, (unsigned long)left, (unsigned long)thisPass );*/ tr_webRun( w->session, url, range, webResponseFunc, w ); tr_free( range ); tr_free( url ); } }
static char* getTorrentFilename(tr_session const* session, tr_info const* inf, enum tr_metainfo_basename_format format) { char* base = tr_metainfoGetBasename(inf, format); char* filename = tr_strdup_printf("%s" TR_PATH_DELIMITER_STR "%s.torrent", tr_getTorrentDir(session), base); tr_free(base); return filename; }
void libttest_zero_torrent_populate (tr_torrent * tor, bool complete) { tr_file_index_t i; for (i=0; i<tor->info.fileCount; ++i) { int err; uint64_t j; FILE * fp; char * path; char * dirname; const tr_file * file = &tor->info.files[i]; struct stat sb; if (!complete && (i==0)) path = tr_strdup_printf ("%s%c%s.part", tor->currentDir, TR_PATH_DELIMITER, file->name); else path = tr_strdup_printf ("%s%c%s", tor->currentDir, TR_PATH_DELIMITER, file->name); dirname = tr_dirname (path); tr_mkdirp (dirname, 0700); fp = fopen (path, "wb+"); for (j=0; j<file->length; ++j) fputc (((!complete) && (i==0) && (j<tor->info.pieceSize)) ? '\1' : '\0', fp); fclose (fp); tr_free (dirname); tr_free (path); path = tr_torrentFindFile (tor, i); assert (path != NULL); err = errno; errno = 0; stat (path, &sb); assert (errno == 0); errno = err; tr_free (path); } sync (); libttest_blockingTorrentVerify (tor); if (complete) assert (tr_torrentStat(tor)->leftUntilDone == 0); else assert (tr_torrentStat(tor)->leftUntilDone == tor->info.pieceSize); }
static tr_watchdir_status onFileAdded(tr_watchdir_t dir, char const* name, void* context) { tr_session* session = context; if (!tr_str_has_suffix(name, ".torrent")) { return TR_WATCHDIR_IGNORE; } char* filename = tr_buildPath(tr_watchdir_get_path(dir), name, NULL); tr_ctor* ctor = tr_ctorNew(session); int err = tr_ctorSetMetainfoFromFile(ctor, filename); if (err == 0) { tr_torrentNew(ctor, &err, NULL); if (err == TR_PARSE_ERR) { tr_logAddError("Error parsing .torrent file \"%s\"", name); } else { bool trash = false; bool const test = tr_ctorGetDeleteSource(ctor, &trash); tr_logAddInfo("Parsing .torrent file successful \"%s\"", name); if (test && trash) { tr_error* error = NULL; tr_logAddInfo("Deleting input .torrent file \"%s\"", name); if (!tr_sys_path_remove(filename, &error)) { tr_logAddError("Error deleting .torrent file: %s", error->message); tr_error_free(error); } } else { char* new_filename = tr_strdup_printf("%s.added", filename); tr_sys_path_rename(filename, new_filename, NULL); tr_free(new_filename); } } } else { err = TR_PARSE_ERR; } tr_ctorFree(ctor); tr_free(filename); return err == TR_PARSE_ERR ? TR_WATCHDIR_RETRY : TR_WATCHDIR_ACCEPT; }
static char* getResumeFilename( const tr_torrent * tor ) { return tr_strdup_printf( "%s%c%s.%16.16s.resume", tr_getResumeDir( tor->session ), TR_PATH_DELIMITER, tor->info.name, tor->info.hashString ); }
static char* getTorrentFilename (const tr_session * session, const tr_info * inf) { char * base = tr_metainfoGetBasename (inf); char * filename = tr_strdup_printf ("%s" TR_PATH_DELIMITER_STR "%s.torrent", tr_getTorrentDir (session), base); tr_free (base); return filename; }
void libttest_zero_torrent_populate (tr_torrent * tor, bool complete) { tr_file_index_t i; for (i=0; i<tor->info.fileCount; ++i) { int err; uint64_t j; tr_sys_file_t fd; char * path; char * dirname; const tr_file * file = &tor->info.files[i]; if (!complete && (i==0)) path = tr_strdup_printf ("%s%c%s.part", tor->currentDir, TR_PATH_DELIMITER, file->name); else path = tr_strdup_printf ("%s%c%s", tor->currentDir, TR_PATH_DELIMITER, file->name); dirname = tr_sys_path_dirname (path, NULL); tr_sys_dir_create (dirname, TR_SYS_DIR_CREATE_PARENTS, 0700, NULL); fd = tr_sys_file_open (path, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE | TR_SYS_FILE_TRUNCATE, 0600, NULL); for (j=0; j<file->length; ++j) tr_sys_file_write (fd, ((!complete) && (i==0) && (j<tor->info.pieceSize)) ? "\1" : "\0", 1, NULL, NULL); tr_sys_file_close (fd, NULL); tr_free (dirname); tr_free (path); path = tr_torrentFindFile (tor, i); assert (path != NULL); err = errno; assert (tr_sys_path_exists (path, NULL)); errno = err; tr_free (path); } libttest_sync (); libttest_blockingTorrentVerify (tor); if (complete) assert (tr_torrentStat(tor)->leftUntilDone == 0); else assert (tr_torrentStat(tor)->leftUntilDone == tor->info.pieceSize); }
char* tr_sys_path_dirname(char const* path, tr_error** error) { if (path == NULL || path[0] == '\0') { return tr_strdup("."); } if (!is_valid_path(path)) { set_system_error(error, ERROR_PATH_NOT_FOUND); return NULL; } bool const is_unc = is_unc_path(path); if (is_unc && path[2] == '\0') { return tr_strdup(path); } char const* end = path + strlen(path); while (end > path && is_slash(*(end - 1))) { --end; } if (end == path) { return tr_strdup("/"); } char const* name = end; while (name > path && *(name - 1) != ':' && !is_slash(*(name - 1))) { --name; } while (name > path && is_slash(*(name - 1))) { --name; } if (name == path) { return tr_strdup(is_unc ? "\\\\" : "."); } if (name > path && *(name - 1) == ':' && *name != '\0' && !is_slash(*name)) { return tr_strdup_printf("%c:.", path[0]); } return tr_strndup(path, name - path); }
static char* getTorrentFilename( const tr_session * session, const tr_info * inf ) { return tr_strdup_printf( "%s%c%s.%16.16s.torrent", tr_getTorrentDir( session ), TR_PATH_DELIMITER, inf->name, inf->hashString ); }
static int test_strdup_printf (void) { char * s, * s2, * s3; s = tr_strdup_printf ("%s", "test"); check_streq ("test", s); tr_free (s); s = tr_strdup_printf ("%d %s %c %u", -1, "0", '1', 2); check_streq ("-1 0 1 2", s); tr_free (s); s3 = tr_malloc0 (4098); memset (s3, '-', 4097); s3[2047] = 't'; s3[2048] = 'e'; s3[2049] = 's'; s3[2050] = 't'; s2 = tr_malloc0 (4096); memset (s2, '-', 4095); s2[2047] = '%'; s2[2048] = 's'; s = tr_strdup_printf (s2, "test"); check_streq (s3, s); tr_free (s); tr_free (s2); s = tr_strdup_printf ("%s", s3); check_streq (s3, s); tr_free (s); tr_free (s3); s = test_strdup_printf_valist ("\n-%s-%s-%s-\n", "\r", "\t", "\b"); check_streq ("\n-\r-\t-\b-\n", s); tr_free (s); return 0; }
char* tr_metainfoGetBasename (const tr_info * inf) { size_t i; const size_t name_len = strlen (inf->name); char * ret = tr_strdup_printf ("%s.%16.16s", inf->name, inf->hashString); for (i=0; i<name_len; ++i) if (ret[i] == '/') ret[i] = '_'; return ret; }
char* tr_metainfoGetBasename (const tr_info * inf) { size_t i; const char * name = inf->originalName; const size_t name_len = strlen (name); char * ret = tr_strdup_printf ("%s.%16.16s", name, inf->hashString); for (i=0; i<name_len; ++i) if (char_is_path_separator (ret[i])) ret[i] = '_'; return ret; }
static CURL * createEasy( tr_session * s, struct tr_web_task * task ) { const tr_address * addr; CURL * e = curl_easy_init( ); const long verbose = getenv( "TR_CURL_VERBOSE" ) != NULL; if( !task->range && s->isProxyEnabled ) { const long proxyType = getCurlProxyType( s->proxyType ); curl_easy_setopt( e, CURLOPT_PROXY, s->proxy ); curl_easy_setopt( e, CURLOPT_PROXYAUTH, CURLAUTH_ANY ); curl_easy_setopt( e, CURLOPT_PROXYPORT, s->proxyPort ); curl_easy_setopt( e, CURLOPT_PROXYTYPE, proxyType ); } if( !task->range && s->isProxyAuthEnabled ) { char * str = tr_strdup_printf( "%s:%s", s->proxyUsername, s->proxyPassword ); curl_easy_setopt( e, CURLOPT_PROXYUSERPWD, str ); tr_free( str ); } curl_easy_setopt( e, CURLOPT_AUTOREFERER, 1L ); curl_easy_setopt( e, CURLOPT_ENCODING, "gzip;q=1.0, deflate, identity" ); curl_easy_setopt( e, CURLOPT_FOLLOWLOCATION, 1L ); curl_easy_setopt( e, CURLOPT_MAXREDIRS, -1L ); curl_easy_setopt( e, CURLOPT_NOSIGNAL, 1L ); curl_easy_setopt( e, CURLOPT_PRIVATE, task ); #ifdef USE_LIBCURL_SOCKOPT curl_easy_setopt( e, CURLOPT_SOCKOPTFUNCTION, sockoptfunction ); curl_easy_setopt( e, CURLOPT_SOCKOPTDATA, task ); #endif curl_easy_setopt( e, CURLOPT_SSL_VERIFYHOST, 0L ); curl_easy_setopt( e, CURLOPT_SSL_VERIFYPEER, 0L ); curl_easy_setopt( e, CURLOPT_TIMEOUT, getTimeoutFromURL( task->url ) ); curl_easy_setopt( e, CURLOPT_URL, task->url ); curl_easy_setopt( e, CURLOPT_USERAGENT, TR_NAME "/" SHORT_VERSION_STRING ); curl_easy_setopt( e, CURLOPT_VERBOSE, verbose ); curl_easy_setopt( e, CURLOPT_WRITEDATA, task ); curl_easy_setopt( e, CURLOPT_WRITEFUNCTION, writeFunc ); if(( addr = tr_sessionGetPublicAddress( s, TR_AF_INET ))) curl_easy_setopt( e, CURLOPT_INTERFACE, tr_ntop_non_ts( addr ) ); if( task->range ) curl_easy_setopt( e, CURLOPT_RANGE, task->range ); return e; }
char* tr_metainfoGetBasename( const tr_info * inf ) { char *ret, *pch, *name; name = tr_strdup( inf->name ); for( pch=name; pch && *pch; ++pch ) if( *pch == '/' ) *pch = '_'; ret = tr_strdup_printf( "%s.%16.16s", name, inf->hashString ); tr_free( name ); return ret; }
static char* metainfoGetBasenameNameAndPartialHash(tr_info const* inf) { char const* name = inf->originalName; size_t const name_len = strlen(name); char* ret = tr_strdup_printf("%s.%16.16s", name, inf->hashString); for (size_t i = 0; i < name_len; ++i) { if (char_is_path_separator(ret[i])) { ret[i] = '_'; } } return ret; }
static void extract_parts_from_multipart (const struct evkeyvalq * headers, struct evbuffer * body, tr_ptrArray * setme_parts) { const char * content_type = evhttp_find_header (headers, "Content-Type"); const char * in = (const char*) evbuffer_pullup (body, -1); size_t inlen = evbuffer_get_length (body); const char * boundary_key = "boundary="; const char * boundary_key_begin = content_type ? strstr (content_type, boundary_key) : NULL; const char * boundary_val = boundary_key_begin ? boundary_key_begin + strlen (boundary_key) : "arglebargle"; char * boundary = tr_strdup_printf ("--%s", boundary_val); const size_t boundary_len = strlen (boundary); const char * delim = tr_memmem (in, inlen, boundary, boundary_len); while (delim) { size_t part_len; const char * part = delim + boundary_len; inlen -= (part - in); in = part; delim = tr_memmem (in, inlen, boundary, boundary_len); part_len = delim ? (size_t)(delim - part) : inlen; if (part_len) { const char * rnrn = tr_memmem (part, part_len, "\r\n\r\n", 4); if (rnrn) { struct tr_mimepart * p = tr_new (struct tr_mimepart, 1); p->headers_len = (size_t) (rnrn - part); p->headers = tr_strndup (part, p->headers_len); p->body_len = (size_t) ((part + part_len) - (rnrn + 4)); p->body = tr_strndup (rnrn+4, p->body_len); tr_ptrArrayAppend (setme_parts, p); } } } tr_free (boundary); }
void tr_fastResumeRemove( const tr_torrent * tor ) { const char * cacheDir = tr_getResumeDir( tor->session ); const char * hash = tor->info.hashString; if( tor->session->tag ) { char * path = tr_strdup_printf( "%s" TR_PATH_DELIMITER_STR "%s-%s", cacheDir, hash, tor->session->tag ); unlink( path ); tr_free( path ); } else { char * path = tr_buildPath( cacheDir, hash, NULL ); unlink( path ); tr_free( path ); } }
static void handle_clutch( struct evhttp_request * req, struct tr_rpc_server * server ) { const char * clutchDir = tr_getClutchDir( server->session ); assert( !strncmp( req->uri, "/transmission/web/", 18 ) ); if( !clutchDir || !*clutchDir ) { send_simple_response( req, HTTP_NOTFOUND, "<p>Couldn't find Transmission's web interface files!</p>" "<p>Users: to tell Transmission where to look, " "set the TRANSMISSION_WEB_HOME environmental " "variable to the folder where the web interface's " "index.html is located.</p>" "<p>Package Builders: to set a custom default at compile time, " "#define PACKAGE_DATA_DIR in libtransmission/platform.c " "or tweak tr_getClutchDir() by hand.</p>" ); } else { char * pch; char * subpath; char * filename; subpath = tr_strdup( req->uri + 18 ); if(( pch = strchr( subpath, '?' ))) *pch = '\0'; filename = tr_strdup_printf( "%s%s%s", clutchDir, TR_PATH_DELIMITER_STR, subpath && *subpath ? subpath : "index.html" ); serve_file( req, server, filename ); tr_free( filename ); tr_free( subpath ); } }
static void onFileAdded (tr_session * session, const char * dir, const char * file) { char * filename = tr_buildPath (dir, file, NULL); tr_ctor * ctor = tr_ctorNew (session); int err = tr_ctorSetMetainfoFromFile (ctor, filename); if (!err) { tr_torrentNew (ctor, &err, NULL); if (err == TR_PARSE_ERR) tr_logAddError ("Error parsing .torrent file \"%s\"", file); else { bool trash = false; int test = tr_ctorGetDeleteSource (ctor, &trash); tr_logAddInfo ("Parsing .torrent file successful \"%s\"", file); if (!test && trash) { tr_logAddInfo ("Deleting input .torrent file \"%s\"", file); if (tr_remove (filename)) tr_logAddError ("Error deleting .torrent file: %s", tr_strerror (errno)); } else { char * new_filename = tr_strdup_printf ("%s.added", filename); tr_rename (filename, new_filename); tr_free (new_filename); } } } tr_ctorFree (ctor); tr_free (filename); }
static uint8_t* loadResumeFile( const tr_torrent * tor, size_t * len ) { uint8_t * ret = NULL; const char * cacheDir = tr_getResumeDir( tor->session ); const char * hash = tor->info.hashString; if( !ret && tor->session->tag ) { char * path = tr_strdup_printf( "%s" TR_PATH_DELIMITER_STR "%s-%s", cacheDir, hash, tor->session->tag ); ret = tr_loadFile( path, len ); tr_free( path ); } if( !ret ) { char * path = tr_buildPath( cacheDir, hash, NULL ); ret = tr_loadFile( path, len ); tr_free( path ); } return ret; }
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 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 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_benc top; int64_t intVal; tr_benc * files; const char * str; const int benc_loaded = !tr_bencLoad( msg, msglen, &top, NULL ); if( benc_loaded ) { if( tr_bencDictFindStr( &top, "failure reason", &str ) ) response->errmsg = tr_strdup( str ); if( tr_bencDictFindInt( &top, "min_request_interval", &intVal ) ) response->min_request_interval = intVal; if( tr_bencDictFindDict( &top, "files", &files ) ) { int i = 0; for( ;; ) { int j; tr_benc * val; const char * key; /* get the next "file" */ if( !tr_bencDictChild( 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( key, row->info_hash, SHA_DIGEST_LENGTH ) ) { if( tr_bencDictFindInt( val, "complete", &intVal ) ) row->seeders = intVal; if( tr_bencDictFindInt( val, "incomplete", &intVal ) ) row->leechers = intVal; if( tr_bencDictFindInt( val, "downloaded", &intVal ) ) row->downloads = intVal; if( tr_bencDictFindInt( val, "downloaders", &intVal ) ) row->downloaders = intVal; break; } } } } tr_bencFree( &top ); } } tr_runInEventThread( session, on_scrape_done_eventthread, data ); }
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_benc benc; const int benc_loaded = !tr_bencLoad( msg, msglen, &benc, NULL ); if( getenv( "TR_CURL_VERBOSE" ) != NULL ) { struct evbuffer * buf = tr_bencToBuf( &benc, TR_FMT_JSON ); fprintf( stderr, "Announce response:\n< %s\n", evbuffer_pullup( buf, -1 ) ); tr_free( buf ); } if( benc_loaded && tr_bencIsDict( &benc ) ) { int64_t i; size_t rawlen; tr_benc * tmp; const char * str; const uint8_t * raw; if( tr_bencDictFindStr( &benc, "failure reason", &str ) ) response->errmsg = tr_strdup( str ); if( tr_bencDictFindStr( &benc, "warning message", &str ) ) response->warning = tr_strdup( str ); if( tr_bencDictFindInt( &benc, "interval", &i ) ) response->interval = i; if( tr_bencDictFindInt( &benc, "min interval", &i ) ) response->min_interval = i; if( tr_bencDictFindStr( &benc, "tracker id", &str ) ) response->tracker_id_str = tr_strdup( str ); if( tr_bencDictFindInt( &benc, "complete", &i ) ) response->seeders = i; if( tr_bencDictFindInt( &benc, "incomplete", &i ) ) response->leechers = i; if( tr_bencDictFindInt( &benc, "downloaded", &i ) ) response->downloads = i; if( tr_bencDictFindRaw( &benc, "peers6", &raw, &rawlen ) ) { dbgmsg( data->log_name, "got a peers6 length of %zu", rawlen ); response->pex6 = tr_peerMgrCompact6ToPex( raw, rawlen, NULL, 0, &response->pex6_count ); } if( tr_bencDictFindRaw( &benc, "peers", &raw, &rawlen ) ) { dbgmsg( data->log_name, "got a compact peers length of %zu", rawlen ); response->pex = tr_peerMgrCompactToPex( raw, rawlen, NULL, 0, &response->pex_count ); } else if( tr_bencDictFindList( &benc, "peers", &tmp ) ) { response->pex = listToPex( tmp, &response->pex_count ); dbgmsg( data->log_name, "got a peers list with %zu entries", response->pex_count ); } } if( benc_loaded ) tr_bencFree( &benc ); } tr_runInEventThread( session, on_announce_done_eventthread, data ); }
int main (int argc, char * argv[]) { char * out2 = NULL; tr_metainfo_builder * b = NULL; tr_logSetLevel (TR_LOG_ERROR); if (parseCommandLine (argc, (const char**)argv)) return EXIT_FAILURE; if (showVersion) { fprintf (stderr, MY_NAME" "LONG_VERSION_STRING"\n"); return EXIT_SUCCESS; } if (!infile) { fprintf (stderr, "ERROR: No input file or directory specified.\n"); tr_getopt_usage (MY_NAME, getUsage (), options); fprintf (stderr, "\n"); return EXIT_FAILURE; } if (outfile == NULL) { char * base = tr_basename (infile); char * end = tr_strdup_printf ("%s.torrent", base); char * cwd = tr_getcwd (); outfile = out2 = tr_buildPath (cwd, end, NULL); tr_free (cwd); tr_free (end); tr_free (base); } if (!trackerCount) { if (isPrivate) { fprintf (stderr, "ERROR: no trackers specified for a private torrent\n"); return EXIT_FAILURE; } else { printf ("WARNING: no trackers specified\n"); } } printf ("Creating torrent \"%s\" ...", outfile); fflush (stdout); b = tr_metaInfoBuilderCreate (infile); if (piecesize_kib != 0) tr_metaInfoBuilderSetPieceSize (b, piecesize_kib * KiB); tr_makeMetaInfo (b, outfile, trackers, trackerCount, comment, isPrivate); while (!b->isDone) { tr_wait_msec (500); putc ('.', stdout); fflush (stdout); } putc (' ', stdout); switch (b->result) { case TR_MAKEMETA_OK: printf ("done!"); break; case TR_MAKEMETA_URL: printf ("bad announce URL: \"%s\"", b->errfile); break; case TR_MAKEMETA_IO_READ: printf ("error reading \"%s\": %s", b->errfile, tr_strerror (b->my_errno)); break; case TR_MAKEMETA_IO_WRITE: printf ("error writing \"%s\": %s", b->errfile, tr_strerror (b->my_errno)); break; case TR_MAKEMETA_CANCELLED: printf ("cancelled"); break; } putc ('\n', stdout); tr_metaInfoBuilderFree (b); tr_free (out2); return EXIT_SUCCESS; }
static int test_single_directory_impl (const tr_tracker_info * trackers, const size_t trackerCount, const void ** payloads, const size_t * payloadSizes, const size_t payloadCount, const char * comment, const bool isPrivate) { char* sandbox; char* torrent_file; tr_metainfo_builder* builder; tr_ctor * ctor; tr_parse_result parse_result; tr_info inf; char * top; char ** files; size_t totalSize; size_t i; char* tmpstr; /* set up our local test sandbox */ sandbox = libtest_sandbox_create(); /* create the top temp directory */ top = tr_buildPath (sandbox, "folder.XXXXXX", NULL); tr_sys_dir_create_temp (top, NULL); /* build the payload files that go into the top temp directory */ files = tr_new (char*, payloadCount); totalSize = 0; for (i=0; i<payloadCount; i++) { char tmpl[16]; tr_snprintf (tmpl, sizeof(tmpl), "file.%04zu%s", i, "XXXXXX"); files[i] = tr_buildPath (top, tmpl, NULL); libtest_create_tmpfile_with_contents (files[i], payloads[i], payloadSizes[i]); totalSize += payloadSizes[i]; } libttest_sync (); /* init the builder */ builder = tr_metaInfoBuilderCreate (top); check (!builder->abortFlag); check_streq (top, builder->top); check_int_eq (payloadCount, builder->fileCount); check_int_eq (totalSize, builder->totalSize); check (builder->isFolder); for (i=0; i<builder->fileCount; i++) { check_streq (files[i], builder->files[i].filename); check_int_eq (payloadSizes[i], builder->files[i].size); } /* call tr_makeMetaInfo() to build the .torrent file */ torrent_file = tr_strdup_printf ("%s.torrent", top); tr_makeMetaInfo (builder, torrent_file, trackers, trackerCount, comment, isPrivate); check (isPrivate == builder->isPrivate); check_streq (torrent_file, builder->outputFile); check_streq (comment, builder->comment); check_int_eq (trackerCount, builder->trackerCount); while (!builder->isDone) tr_wait_msec (100); /* now let's check our work: parse the .torrent file */ ctor = tr_ctorNew (NULL); libttest_sync (); tr_ctorSetMetainfoFromFile (ctor, torrent_file); parse_result = tr_torrentParse (ctor, &inf); check_int_eq (TR_PARSE_OK, parse_result); /* quick check of some of the parsed metainfo */ check_int_eq (totalSize, inf.totalSize); tmpstr = tr_sys_path_basename (top, NULL); check_streq (tmpstr, inf.name); tr_free (tmpstr); check_streq (comment, inf.comment); check_int_eq (payloadCount, inf.fileCount); check_int_eq (isPrivate, inf.isPrivate); check_int_eq (builder->isFolder, inf.isFolder); check_int_eq (trackerCount, inf.trackerCount); /* cleanup */ tr_free (torrent_file); tr_ctorFree (ctor); tr_metainfoFree (&inf); tr_metaInfoBuilderFree (builder); for (i=0; i<payloadCount; i++) tr_free (files[i]); tr_free (files); libtest_sandbox_destroy (sandbox); tr_free (sandbox); tr_free (top); return 0; }
static void addTask( void * vtask ) { struct tr_web_task * task = vtask; const tr_session * session = task->session; if( ( session == NULL ) || ( session->web == NULL ) ) return; if( !task->resolved_host ) { dbgmsg( "couldn't resolve host for \"%s\"... task failed", task->url ); task_finish( task, 0 ); } else { CURL * e = curl_easy_init( ); struct tr_web * web = session->web; const int timeout = getTimeoutFromURL( task->url ); const long verbose = getenv( "TR_CURL_VERBOSE" ) != NULL; const char * user_agent = TR_NAME "/" SHORT_VERSION_STRING; /* insert the resolved host into the URL s.t. curl's DNS won't block * even if -- like on most OSes -- it wasn't built with C-Ares :( * "http://www.craptrackular.org/announce?key=val&key2=..." becomes * "http://127.0.0.1/announce?key=val&key2=..." */ { char * host; struct evbuffer * buf = evbuffer_new( ); char * pch = strstr( task->url, task->host ); char * tail = pch + strlen( task->host ); evbuffer_add( buf, task->url, pch - task->url ); evbuffer_add_printf( buf, "%s", task->resolved_host ); evbuffer_add_printf( buf, "%s", tail ); task->resolved_url = tr_strndup( EVBUFFER_DATA( buf ), EVBUFFER_LENGTH( buf ) ); dbgmsg( "old url: \"%s\" -- new url: \"%s\"", task->url, task->resolved_url ); evbuffer_free( buf ); /* Manually add a Host: argument that refers to the true URL */ if( ( ( task->port <= 0 ) ) || ( ( task->port == 80 ) && !strncmp( task->url, "http://", 7 ) ) || ( ( task->port == 443 ) && !strncmp( task->url, "https://", 8 ) ) ) host = tr_strdup_printf( "Host: %s", task->host ); else host = tr_strdup_printf( "Host: %s:%d", task->host, task->port ); task->slist = curl_slist_append( NULL, host ); task->slist = curl_slist_append( task->slist, "Accept:" ); curl_easy_setopt( e, CURLOPT_HTTPHEADER, task->slist ); tr_free( host ); } dbgmsg( "adding task #%lu [%s]", task->tag, task->resolved_url ? task->resolved_url : task->url ); if( !task->range && session->isProxyEnabled ) { curl_easy_setopt( e, CURLOPT_PROXY, session->proxy ); curl_easy_setopt( e, CURLOPT_PROXYAUTH, CURLAUTH_ANY ); curl_easy_setopt( e, CURLOPT_PROXYPORT, session->proxyPort ); curl_easy_setopt( e, CURLOPT_PROXYTYPE, getCurlProxyType( session->proxyType ) ); } if( !task->range && session->isProxyAuthEnabled ) { char * str = tr_strdup_printf( "%s:%s", session->proxyUsername, session->proxyPassword ); curl_easy_setopt( e, CURLOPT_PROXYUSERPWD, str ); tr_free( str ); } task->easy = e; task->multi = web->multi; /* use our own timeout instead of CURLOPT_TIMEOUT because the latter * doesn't play nicely with curl_multi. See curl bug #2501457 */ task->timer_event_isSet = TRUE; evtimer_set( &task->timer_event, task_timeout_cb, task ); tr_timerAdd( &task->timer_event, timeout, 0 ); curl_easy_setopt( e, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 ); curl_easy_setopt( e, CURLOPT_SOCKOPTFUNCTION, sockoptfunction ); curl_easy_setopt( e, CURLOPT_SOCKOPTDATA, task ); curl_easy_setopt( e, CURLOPT_WRITEDATA, task ); curl_easy_setopt( e, CURLOPT_WRITEFUNCTION, writeFunc ); curl_easy_setopt( e, CURLOPT_DNS_CACHE_TIMEOUT, MIN_DNS_CACHE_TIME ); curl_easy_setopt( e, CURLOPT_FOLLOWLOCATION, 1L ); curl_easy_setopt( e, CURLOPT_AUTOREFERER, 1L ); curl_easy_setopt( e, CURLOPT_FORBID_REUSE, 1L ); curl_easy_setopt( e, CURLOPT_MAXREDIRS, -1L ); curl_easy_setopt( e, CURLOPT_PRIVATE, task ); curl_easy_setopt( e, CURLOPT_SSL_VERIFYHOST, 0L ); curl_easy_setopt( e, CURLOPT_SSL_VERIFYPEER, 0L ); curl_easy_setopt( e, CURLOPT_URL, task->resolved_url ? task->resolved_url : task->url ); curl_easy_setopt( e, CURLOPT_USERAGENT, user_agent ); curl_easy_setopt( e, CURLOPT_VERBOSE, verbose ); if( web->haveAddr ) curl_easy_setopt( e, CURLOPT_INTERFACE, tr_ntop_non_ts( &web->addr ) ); if( task->range ) curl_easy_setopt( e, CURLOPT_RANGE, task->range ); if( curl_multi_add_handle( web->multi, e ) == CURLM_OK ) ++web->taskCount; } }
static int test_single_file_impl (const tr_tracker_info * trackers, const size_t trackerCount, const void * payload, const size_t payloadSize, const char * comment, bool isPrivate) { char* sandbox; char* input_file; char* torrent_file; tr_metainfo_builder* builder; tr_ctor * ctor; tr_parse_result parse_result; tr_info inf; char * tmpstr; /* set up our local test sandbox */ sandbox = libtest_sandbox_create(); /* create a single input file */ input_file = tr_buildPath (sandbox, "test.XXXXXX", NULL); libtest_create_tmpfile_with_contents (input_file, payload, payloadSize); builder = tr_metaInfoBuilderCreate (input_file); check_streq (input_file, builder->top); check_int_eq (1, builder->fileCount); check_streq (input_file, builder->files[0].filename); check_int_eq (payloadSize, builder->files[0].size); check_int_eq (payloadSize, builder->totalSize); check (!builder->isFolder); check (!builder->abortFlag); /* have tr_makeMetaInfo() build the .torrent file */ torrent_file = tr_strdup_printf ("%s.torrent", input_file); tr_makeMetaInfo (builder, torrent_file, trackers, trackerCount, comment, isPrivate); check (isPrivate == builder->isPrivate); check_streq (torrent_file, builder->outputFile); check_streq (comment, builder->comment); check_int_eq (trackerCount, builder->trackerCount); while (!builder->isDone) tr_wait_msec (100); /* now let's check our work: parse the .torrent file */ ctor = tr_ctorNew (NULL); libttest_sync (); tr_ctorSetMetainfoFromFile (ctor, torrent_file); parse_result = tr_torrentParse (ctor, &inf); check_int_eq (TR_PARSE_OK, parse_result); /* quick check of some of the parsed metainfo */ check_int_eq (payloadSize, inf.totalSize); tmpstr = tr_sys_path_basename (input_file, NULL); check_streq (tmpstr, inf.name); tr_free (tmpstr); check_streq (comment, inf.comment); check_int_eq (1, inf.fileCount); check_int_eq (isPrivate, inf.isPrivate); check (!inf.isFolder); check_int_eq (trackerCount, inf.trackerCount); /* cleanup */ tr_free (torrent_file); tr_free (input_file); tr_ctorFree (ctor); tr_metainfoFree (&inf); tr_metaInfoBuilderFree (builder); libtest_sandbox_destroy (sandbox); tr_free (sandbox); return 0; }