Пример #1
0
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" );
}
Пример #2
0
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;
}
Пример #3
0
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 );
    }
}
Пример #4
0
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;
}
Пример #5
0
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);
}
Пример #6
0
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;
}
Пример #7
0
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 );
}
Пример #8
0
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;
}
Пример #9
0
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);
}
Пример #10
0
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);
}
Пример #11
0
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 );
}
Пример #12
0
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;
}
Пример #13
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;
}
Пример #14
0
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;
}
Пример #15
0
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;
}
Пример #16
0
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;
}
Пример #17
0
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;
}
Пример #18
0
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);
}
Пример #19
0
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 );
    }
}
Пример #20
0
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 );
    }
}
Пример #21
0
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);
}
Пример #22
0
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;
}
Пример #23
0
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);
}
Пример #24
0
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);
}
Пример #25
0
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 );
}
Пример #26
0
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 );
}
Пример #27
0
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;
}
Пример #28
0
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;
}
Пример #29
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;
    }
}
Пример #30
0
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;
}