#377: preliminary https support. this commit probably breaks mac and cli and is not for the faint of heart.
This commit is contained in:
parent
3a609ecc87
commit
7ef2511ca8
|
@ -1,5 +1,5 @@
|
|||
AM_CPPFLAGS = -I$(top_srcdir) $(LIBEVENT_CPPFLAGS)
|
||||
AM_CFLAGS = $(OPENSSL_CFLAGS) $(PTHREAD_CFLAGS)
|
||||
AM_CFLAGS = $(OPENSSL_CFLAGS) $(LIBCURL_CFLAGS) $(PTHREAD_CFLAGS)
|
||||
|
||||
bin_PROGRAMS = transmissioncli
|
||||
|
||||
|
@ -8,9 +8,13 @@ dist_man_MANS = transmissioncli.1
|
|||
transmissioncli_SOURCES = transmissioncli.c
|
||||
|
||||
transmissioncli_LDADD = \
|
||||
$(top_builddir)/libtransmission/libtransmission.a \
|
||||
$(top_builddir)/third-party/libevent/libevent.la \
|
||||
$(top_builddir)/third-party/libnatpmp/libnatpmp.a \
|
||||
$(top_builddir)/third-party/miniupnp/libminiupnp.a \
|
||||
$(INTLLIBS) $(OPENSSL_LIBS) $(PTHREAD_LIBS) -lm
|
||||
$(top_builddir)/libtransmission/libtransmission.a \
|
||||
$(top_builddir)/third-party/libevent/libevent.la \
|
||||
$(top_builddir)/third-party/libnatpmp/libnatpmp.a \
|
||||
$(top_builddir)/third-party/miniupnp/libminiupnp.a \
|
||||
$(INTLLIBS) \
|
||||
$(OPENSSL_LIBS) \
|
||||
$(LIBCURL_LIBS) \
|
||||
$(PTHREAD_LIBS) \
|
||||
-lm
|
||||
|
||||
|
|
|
@ -10,12 +10,14 @@ AC_CONFIG_SRCDIR(libtransmission/transmission.h)
|
|||
AM_INIT_AUTOMAKE([1.9 tar-ustar])
|
||||
AC_PROG_LIBTOOL
|
||||
|
||||
CURL_MINIMUM=7.16.0
|
||||
GIO_MINIMUM=2.15.5
|
||||
GLIB_MINIMUM=2.6.0
|
||||
GTK_MINIMUM=2.6.0
|
||||
WX_MINIMUM=2.6.0
|
||||
LIBNOTIFY_MINIMUM=0.4.4
|
||||
DBUS_GLIB_MINIMUM=0.70
|
||||
AC_SUBST(CURL_MINIMUM)
|
||||
AC_SUBST(GIO_MINIMUM)
|
||||
AC_SUBST(GLIB_MINIMUM)
|
||||
AC_SUBST(GTK_MINIMUM)
|
||||
|
@ -41,6 +43,7 @@ ACX_PTHREAD
|
|||
AC_SEARCH_LIBS([socket], [socket net])
|
||||
AC_SEARCH_LIBS([gethostbyname], [nsl bind])
|
||||
PKG_CHECK_MODULES(OPENSSL, [openssl >= 0.9.4])
|
||||
PKG_CHECK_MODULES(LIBCURL, [libcurl >= 0.9.4])
|
||||
|
||||
AC_SYS_LARGEFILE
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
AM_CPPFLAGS = -I@top_srcdir@ $(LIBEVENT_CPPFLAGS)
|
||||
AM_CFLAGS = $(OPENSSL_CFLAGS) $(PTHREAD_CFLAGS)
|
||||
AM_CFLAGS = $(OPENSSL_CFLAGS) $(LIBCURL_CFLAGS) $(PTHREAD_CFLAGS)
|
||||
|
||||
noinst_LIBRARIES = libdaemon.a
|
||||
|
||||
|
@ -32,7 +32,10 @@ COMMON_LDADD = \
|
|||
$(top_builddir)/third-party/miniupnp/libminiupnp.a \
|
||||
$(top_builddir)/third-party/libnatpmp/libnatpmp.a \
|
||||
$(top_builddir)/third-party/libevent/libevent.la \
|
||||
$(INTLLIBS) $(OPENSSL_LIBS) $(PTHREAD_LIBS) -lm
|
||||
$(INTLLIBS) \
|
||||
$(OPENSSL_LIBS) \
|
||||
$(LIBCURL_LIBS) \
|
||||
$(PTHREAD_LIBS) -lm
|
||||
|
||||
transmission_daemon_SOURCES = daemon.c server.c torrents.c
|
||||
transmission_daemon_LDADD = $(COMMON_LDADD)
|
||||
|
|
|
@ -9,6 +9,7 @@ AM_CPPFLAGS = \
|
|||
AM_CFLAGS = \
|
||||
$(GTK_CFLAGS) \
|
||||
$(OPENSSL_CFLAGS) \
|
||||
$(LIBCURL_CFLAGS) \
|
||||
$(PTHREAD_CFLAGS) \
|
||||
$(GIO_CFLAGS) \
|
||||
$(DBUS_GLIB_CFLAGS) \
|
||||
|
@ -78,6 +79,7 @@ transmission_LDADD = \
|
|||
$(LIBNOTIFY_LIBS) \
|
||||
$(DBUS_GLIB_LIBS) \
|
||||
$(OPENSSL_LIBS) \
|
||||
$(LIBCURL_LIBS) \
|
||||
$(PTHREAD_LIBS) -lm
|
||||
|
||||
DESKTOP_IN_FILES=transmission.desktop.in
|
||||
|
|
|
@ -1119,9 +1119,7 @@ tracker_page_new( TrTorrent * gtor )
|
|||
GtkWidget * l;
|
||||
int row = 0;
|
||||
const char * s;
|
||||
char * tmp;
|
||||
struct tracker_page * page = g_new0( struct tracker_page, 1 );
|
||||
const tr_tracker_info * track;
|
||||
const tr_info * info = tr_torrent_info (gtor);
|
||||
|
||||
page->gtor = gtor;
|
||||
|
@ -1147,14 +1145,9 @@ tracker_page_new( TrTorrent * gtor )
|
|||
hig_workarea_add_section_divider( t, &row );
|
||||
hig_workarea_add_section_title( t, &row, _( "Announce" ) );
|
||||
|
||||
track = info->trackerList->list;
|
||||
tmp = track->port==80
|
||||
? g_strdup_printf( "http://%s%s", track->address, track->announce )
|
||||
: g_strdup_printf( "http://%s:%d%s", track->address, track->port, track->announce );
|
||||
l = gtk_label_new( tmp );
|
||||
l = gtk_label_new( info->trackers[0].announce );
|
||||
gtk_label_set_ellipsize( GTK_LABEL( l ), PANGO_ELLIPSIZE_END );
|
||||
hig_workarea_add_row (t, &row, _( "Tracker:" ), l, NULL);
|
||||
g_free( tmp );
|
||||
|
||||
s = _( "Last announce at:" );
|
||||
l = gtk_label_new( NULL );
|
||||
|
|
|
@ -283,8 +283,8 @@ compareByTracker( GtkTreeModel * model,
|
|||
const tr_torrent *ta, *tb;
|
||||
gtk_tree_model_get( model, a, MC_TORRENT_RAW, &ta, -1 );
|
||||
gtk_tree_model_get( model, b, MC_TORRENT_RAW, &tb, -1 );
|
||||
return strcmp( tr_torrentInfo(ta)->primaryAddress,
|
||||
tr_torrentInfo(tb)->primaryAddress );
|
||||
return strcmp( tr_torrentInfo(ta)->trackers[0].announce,
|
||||
tr_torrentInfo(tb)->trackers[0].announce );
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -274,7 +274,7 @@ checkFilterText( filter_text_mode_t filter_text_mode,
|
|||
break;
|
||||
|
||||
case FILTER_TEXT_MODE_TRACKER:
|
||||
pch = g_ascii_strdown( torInfo->primaryAddress, -1 );
|
||||
pch = g_ascii_strdown( torInfo->trackers[0].announce, -1 );
|
||||
ret = !text || ( strstr( pch, text ) != NULL );
|
||||
g_free( pch );
|
||||
break;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
AM_CPPFLAGS = -I. -I$(top_srcdir) -I$(top_srcdir)/third-party/ -D__TRANSMISSION__ $(LIBEVENT_CPPFLAGS)
|
||||
AM_CFLAGS = $(OPENSSL_CFLAGS) $(PTHREAD_CFLAGS)
|
||||
AM_CFLAGS = $(OPENSSL_CFLAGS) $(LIBCURL_CFLAGS) $(PTHREAD_CFLAGS)
|
||||
|
||||
noinst_LIBRARIES = libtransmission.a
|
||||
|
||||
|
@ -37,7 +37,8 @@ libtransmission_a_SOURCES = \
|
|||
trevent.c \
|
||||
upnp.c \
|
||||
utils.c \
|
||||
verify.c
|
||||
verify.c \
|
||||
web.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
bencode.h \
|
||||
|
@ -75,7 +76,8 @@ noinst_HEADERS = \
|
|||
trevent.h \
|
||||
upnp.h \
|
||||
utils.h \
|
||||
verify.h
|
||||
verify.h \
|
||||
web.h
|
||||
|
||||
bin_PROGRAMS = benc2php
|
||||
|
||||
|
@ -92,7 +94,11 @@ APPS_LDADD = \
|
|||
$(top_builddir)/third-party/miniupnp/libminiupnp.a \
|
||||
$(top_builddir)/third-party/libnatpmp/libnatpmp.a \
|
||||
$(top_builddir)/third-party/libevent/libevent.la \
|
||||
$(INTLLIBS) $(OPENSSL_LIBS) $(PTHREAD_LIBS) -lm
|
||||
$(INTLLIBS) \
|
||||
$(OPENSSL_LIBS) \
|
||||
$(LIBCURL_LIBS) \
|
||||
$(PTHREAD_LIBS) \
|
||||
-lm
|
||||
|
||||
benc2php_SOURCES = benc2php.c
|
||||
benc2php_LDADD = $(APPS_LDADD)
|
||||
|
|
|
@ -531,8 +531,6 @@ static void
|
|||
filltracker( tr_benc * val, const tr_tracker_info * tk )
|
||||
{
|
||||
tr_bencInitDict( val, 4 );
|
||||
tr_bencDictAddStr( val, "address", tk->address );
|
||||
tr_bencDictAddInt( val, "port", tk->port );
|
||||
tr_bencDictAddStr( val, "announce", tk->announce );
|
||||
if( tk->scrape )
|
||||
tr_bencDictAddStr( val, "scrape", tk->scrape );
|
||||
|
@ -554,7 +552,7 @@ ipc_addinfo( tr_benc * list,
|
|||
int types )
|
||||
{
|
||||
tr_benc * dict;
|
||||
int ii, jj, kk;
|
||||
int ii, jj;
|
||||
tr_file_index_t ff;
|
||||
const tr_info * inf = tr_torrentInfo( tor );
|
||||
|
||||
|
@ -628,17 +626,19 @@ ipc_addinfo( tr_benc * list,
|
|||
case IPC_INF_SIZE:
|
||||
tr_bencInitInt( item, inf->totalSize );
|
||||
break;
|
||||
case IPC_INF_TRACKERS:
|
||||
tr_bencInitList( item, inf->trackerTiers );
|
||||
for( jj = 0; inf->trackerTiers > jj; jj++ )
|
||||
{
|
||||
tr_benc * tier = tr_bencListAdd( item );
|
||||
tr_bencInitList( tier, inf->trackerList[jj].count );
|
||||
for( kk = 0; inf->trackerList[jj].count > kk; kk++ )
|
||||
filltracker( tr_bencListAdd( tier ),
|
||||
&inf->trackerList[jj].list[kk] );
|
||||
case IPC_INF_TRACKERS: {
|
||||
int prevTier = -1;
|
||||
tr_benc * tier = NULL;
|
||||
tr_bencInitList( item, 0 );
|
||||
for( jj=0; jj<inf->trackerCount; ++jj ) {
|
||||
if( prevTier != inf->trackers[jj].tier ) {
|
||||
prevTier = inf->trackers[jj].tier;
|
||||
tier = tr_bencListAddList( item, 0 );
|
||||
}
|
||||
filltracker( tr_bencListAdd( tier ), &inf->trackers[jj] );
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert( 0 );
|
||||
break;
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
#include <sys/stat.h>
|
||||
#include <unistd.h> /* unlink, stat */
|
||||
|
||||
#include <event.h> /* struct evbuffer */
|
||||
|
||||
#include "transmission.h"
|
||||
#include "bencode.h"
|
||||
#include "crypto.h" /* tr_sha1 */
|
||||
|
@ -330,7 +332,7 @@ tr_metainfoParse( const tr_handle * handle,
|
|||
void tr_metainfoFree( tr_info * inf )
|
||||
{
|
||||
tr_file_index_t ff;
|
||||
int i, j;
|
||||
int i;
|
||||
|
||||
for( ff=0; ff<inf->fileCount; ++ff )
|
||||
tr_free( inf->files[ff].name );
|
||||
|
@ -341,14 +343,12 @@ void tr_metainfoFree( tr_info * inf )
|
|||
tr_free( inf->creator );
|
||||
tr_free( inf->torrent );
|
||||
tr_free( inf->name );
|
||||
tr_free( inf->primaryAddress );
|
||||
|
||||
for( i=0; i<inf->trackerTiers; ++i ) {
|
||||
for( j=0; j<inf->trackerList[i].count; ++j )
|
||||
tr_trackerInfoClear( &inf->trackerList[i].list[j] );
|
||||
tr_free( inf->trackerList[i].list );
|
||||
for( i=0; i<inf->trackerCount; ++i ) {
|
||||
tr_free( inf->trackers[i].announce );
|
||||
tr_free( inf->trackers[i].scrape );
|
||||
}
|
||||
tr_free( inf->trackerList );
|
||||
tr_free( inf->trackers );
|
||||
|
||||
memset( inf, '\0', sizeof(tr_info) );
|
||||
}
|
||||
|
@ -411,208 +411,95 @@ getfile( char ** setme, const char * prefix, tr_benc * name )
|
|||
|
||||
static int getannounce( tr_info * inf, tr_benc * meta )
|
||||
{
|
||||
tr_benc * val, * urlval;
|
||||
char * address, * announce;
|
||||
int ii, jj, port, random;
|
||||
tr_tracker_info * sublist;
|
||||
void * swapping;
|
||||
const char * str;
|
||||
tr_tracker_info * trackers = NULL;
|
||||
int trackerCount = 0;
|
||||
tr_benc * tiers;
|
||||
|
||||
/* Announce-list */
|
||||
val = tr_bencDictFind( meta, "announce-list" );
|
||||
if( tr_bencIsList(val) && 0 < val->val.l.count )
|
||||
if( tr_bencDictFindList( meta, "announce-list", &tiers ) )
|
||||
{
|
||||
inf->trackerTiers = 0;
|
||||
inf->trackerList = calloc( val->val.l.count,
|
||||
sizeof( inf->trackerList[0] ) );
|
||||
int n;
|
||||
int i, j;
|
||||
|
||||
/* iterate through the announce-list's tiers */
|
||||
for( ii = 0; ii < val->val.l.count; ii++ )
|
||||
{
|
||||
int subcount = 0;
|
||||
tr_benc * subval = &val->val.l.vals[ii];
|
||||
n = 0;
|
||||
for( i=0; i<tiers->val.l.count; ++i )
|
||||
n += tiers->val.l.vals[i].val.l.count;
|
||||
|
||||
if( !tr_bencIsList(subval) || 0 >= subval->val.l.count )
|
||||
continue;
|
||||
trackers = tr_new0( tr_tracker_info, n );
|
||||
trackerCount = 0;
|
||||
|
||||
sublist = calloc( subval->val.l.count, sizeof( sublist[0] ) );
|
||||
|
||||
/* iterate through the tier's items */
|
||||
for( jj = 0; jj < subval->val.l.count; jj++ )
|
||||
{
|
||||
tr_tracker_info tmp;
|
||||
|
||||
urlval = &subval->val.l.vals[jj];
|
||||
if( TYPE_STR != urlval->type ||
|
||||
tr_trackerInfoInit( &tmp, urlval->val.s.s, urlval->val.s.i ) )
|
||||
{
|
||||
continue;
|
||||
for( i=0; i<tiers->val.l.count; ++i ) {
|
||||
const tr_benc * tier = &tiers->val.l.vals[i];
|
||||
for( j=0; tr_bencIsList(tier) && j<tier->val.l.count; ++j ) {
|
||||
const tr_benc * address = &tier->val.l.vals[j];
|
||||
if( tr_bencIsString( address ) && tr_httpIsValidURL( address->val.s.s ) ) {
|
||||
trackers[trackerCount].tier = i;
|
||||
trackers[trackerCount].announce = tr_strndup( address->val.s.s, address->val.s.i );
|
||||
trackers[trackerCount++].scrape = announceToScrape( address->val.s.s );
|
||||
/*fprintf( stderr, "tier %d: %s\n", i, address->val.s.s );*/
|
||||
}
|
||||
|
||||
if( !inf->primaryAddress ) {
|
||||
char buf[1024];
|
||||
snprintf( buf, sizeof(buf), "%s:%d", tmp.address, tmp.port );
|
||||
inf->primaryAddress = tr_strdup( buf );
|
||||
}
|
||||
|
||||
/* place the item info in a random location in the sublist */
|
||||
random = tr_rand( subcount + 1 );
|
||||
if( random != subcount )
|
||||
sublist[subcount] = sublist[random];
|
||||
sublist[random] = tmp;
|
||||
subcount++;
|
||||
}
|
||||
|
||||
/* just use sublist as-is if it's full */
|
||||
if( subcount == subval->val.l.count )
|
||||
{
|
||||
inf->trackerList[inf->trackerTiers].list = sublist;
|
||||
inf->trackerList[inf->trackerTiers].count = subcount;
|
||||
inf->trackerTiers++;
|
||||
}
|
||||
/* if we skipped some of the tier's items then trim the sublist */
|
||||
else if( 0 < subcount )
|
||||
{
|
||||
inf->trackerList[inf->trackerTiers].list = calloc( subcount, sizeof( sublist[0] ) );
|
||||
memcpy( inf->trackerList[inf->trackerTiers].list, sublist,
|
||||
sizeof( sublist[0] ) * subcount );
|
||||
inf->trackerList[inf->trackerTiers].count = subcount;
|
||||
inf->trackerTiers++;
|
||||
free( sublist );
|
||||
}
|
||||
/* drop the whole sublist if we didn't use any items at all */
|
||||
else
|
||||
{
|
||||
free( sublist );
|
||||
}
|
||||
}
|
||||
|
||||
/* did we use any of the tiers? */
|
||||
if( 0 == inf->trackerTiers )
|
||||
{
|
||||
if( !trackerCount ) {
|
||||
tr_inf( _( "Invalid metadata entry \"%s\"" ), "announce-list" );
|
||||
free( inf->trackerList );
|
||||
inf->trackerList = NULL;
|
||||
}
|
||||
/* trim unused sublist pointers */
|
||||
else if( inf->trackerTiers < val->val.l.count )
|
||||
{
|
||||
swapping = inf->trackerList;
|
||||
inf->trackerList = calloc( inf->trackerTiers,
|
||||
sizeof( inf->trackerList[0] ) );
|
||||
memcpy( inf->trackerList, swapping,
|
||||
sizeof( inf->trackerList[0] ) * inf->trackerTiers );
|
||||
free( swapping );
|
||||
tr_free( trackers );
|
||||
trackers = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Regular announce value */
|
||||
val = tr_bencDictFind( meta, "announce" );
|
||||
if( !tr_bencIsString( val ) )
|
||||
if( !trackerCount
|
||||
&& tr_bencDictFindStr( meta, "announce", &str )
|
||||
&& tr_httpIsValidURL( str ) )
|
||||
{
|
||||
tr_err( _( "Missing metadata entry \"%s\"" ), "announce" );
|
||||
return TR_EINVALID;
|
||||
}
|
||||
|
||||
if( !inf->trackerTiers )
|
||||
{
|
||||
char buf[4096], *pch;
|
||||
strlcpy( buf, val->val.s.s, sizeof( buf ) );
|
||||
pch = buf;
|
||||
while( isspace( *pch ) )
|
||||
++pch;
|
||||
|
||||
if( tr_httpParseURL( pch, -1, &address, &port, &announce ) )
|
||||
{
|
||||
tr_err( _( "Invalid announce URL \"%s\"" ), val->val.s.s );
|
||||
return TR_EINVALID;
|
||||
}
|
||||
sublist = calloc( 1, sizeof( sublist[0] ) );
|
||||
sublist[0].address = address;
|
||||
sublist[0].port = port;
|
||||
sublist[0].announce = announce;
|
||||
sublist[0].scrape = announceToScrape( announce );
|
||||
inf->trackerList = calloc( 1, sizeof( inf->trackerList[0] ) );
|
||||
inf->trackerList[0].list = sublist;
|
||||
inf->trackerList[0].count = 1;
|
||||
inf->trackerTiers = 1;
|
||||
|
||||
if( !inf->primaryAddress ) {
|
||||
char buf[1024];
|
||||
snprintf( buf, sizeof(buf), "%s:%d", sublist[0].address, sublist[0].port );
|
||||
inf->primaryAddress = tr_strdup( buf );
|
||||
}
|
||||
|
||||
trackers = tr_new0( tr_tracker_info, 1 );
|
||||
trackers[trackerCount].tier = 0;
|
||||
trackers[trackerCount].announce = tr_strdup( str );
|
||||
trackers[trackerCount++].scrape = announceToScrape( str );
|
||||
/*fprintf( stderr, "single announce: [%s]\n", str );*/
|
||||
}
|
||||
|
||||
inf->trackers = trackers;
|
||||
inf->trackerCount = trackerCount;
|
||||
return TR_OK;
|
||||
}
|
||||
|
||||
static char * announceToScrape( const char * announce )
|
||||
static char *
|
||||
announceToScrape( const char * announce )
|
||||
{
|
||||
char old[] = "announce";
|
||||
int oldlen = 8;
|
||||
char new[] = "scrape";
|
||||
int newlen = 6;
|
||||
char * slash, * scrape;
|
||||
size_t scrapelen, used;
|
||||
char * scrape = NULL;
|
||||
const char * slash;
|
||||
struct evbuffer * buf;
|
||||
|
||||
/* To derive the scrape URL use the following steps:
|
||||
* Begin with the announce URL. Find the last '/' in it.
|
||||
* If the text immediately following that '/' isn't 'announce'
|
||||
* it will be taken as a sign that that tracker doesn't support
|
||||
* the scrape convention. If it does, substitute 'scrape' for
|
||||
* 'announce' to find the scrape page. */
|
||||
|
||||
/* is the last slash followed by "announce"? */
|
||||
slash = strrchr( announce, '/' );
|
||||
if( NULL == slash )
|
||||
{
|
||||
if( !slash )
|
||||
return NULL;
|
||||
}
|
||||
slash++;
|
||||
|
||||
if( 0 != strncmp( slash, old, oldlen ) )
|
||||
{
|
||||
++slash;
|
||||
if( strncmp( slash, "announce", 8 ) )
|
||||
return NULL;
|
||||
}
|
||||
|
||||
scrapelen = strlen( announce ) - oldlen + newlen;
|
||||
scrape = calloc( scrapelen + 1, 1 );
|
||||
if( NULL == scrape )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
assert( ( size_t )( slash - announce ) < scrapelen );
|
||||
memcpy( scrape, announce, slash - announce );
|
||||
used = slash - announce;
|
||||
strncat( scrape, new, scrapelen - used );
|
||||
used += newlen;
|
||||
assert( strlen( scrape ) == used );
|
||||
if( used < scrapelen )
|
||||
{
|
||||
assert( strlen( slash + oldlen ) == scrapelen - used );
|
||||
strncat( scrape, slash + oldlen, scrapelen - used );
|
||||
}
|
||||
/* build the scrape url */
|
||||
buf = evbuffer_new( );
|
||||
evbuffer_add( buf, announce, slash-announce );
|
||||
evbuffer_add( buf, "scrape", 6 );
|
||||
evbuffer_add_printf( buf, "%s", slash+8 );
|
||||
scrape = tr_strdup( ( char * ) EVBUFFER_DATA( buf ) );
|
||||
evbuffer_free( buf );
|
||||
|
||||
return scrape;
|
||||
}
|
||||
|
||||
int
|
||||
tr_trackerInfoInit( tr_tracker_info * info,
|
||||
const char * address,
|
||||
int address_len )
|
||||
{
|
||||
int ret = tr_httpParseURL( address, address_len,
|
||||
&info->address,
|
||||
&info->port,
|
||||
&info->announce );
|
||||
if( !ret )
|
||||
info->scrape = announceToScrape( info->announce );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
tr_trackerInfoClear( tr_tracker_info * info )
|
||||
{
|
||||
tr_free( info->address );
|
||||
tr_free( info->announce );
|
||||
tr_free( info->scrape );
|
||||
memset( info, '\0', sizeof(tr_tracker_info) );
|
||||
}
|
||||
|
||||
void
|
||||
tr_metainfoRemoveSaved( const tr_handle * handle,
|
||||
const tr_info * inf )
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "tracker.h"
|
||||
#include "trevent.h"
|
||||
#include "utils.h"
|
||||
#include "web.h"
|
||||
|
||||
/* Generate a peer id : "-TRxyzb-" + 12 random alphanumeric
|
||||
characters, where x is the major version number, y is the
|
||||
|
@ -92,22 +93,22 @@ tr_getPeerId( void )
|
|||
***/
|
||||
|
||||
tr_encryption_mode
|
||||
tr_getEncryptionMode( tr_handle * handle )
|
||||
tr_getEncryptionMode( tr_session * session )
|
||||
{
|
||||
assert( handle != NULL );
|
||||
assert( session != NULL );
|
||||
|
||||
return handle->encryptionMode;
|
||||
return session->encryptionMode;
|
||||
}
|
||||
|
||||
void
|
||||
tr_setEncryptionMode( tr_handle * handle, tr_encryption_mode mode )
|
||||
tr_setEncryptionMode( tr_session * session, tr_encryption_mode mode )
|
||||
{
|
||||
assert( handle != NULL );
|
||||
assert( session != NULL );
|
||||
assert( mode==TR_ENCRYPTION_PREFERRED
|
||||
|| mode==TR_ENCRYPTION_REQUIRED
|
||||
|| mode==TR_PLAINTEXT_PREFERRED );
|
||||
|
||||
handle->encryptionMode = mode;
|
||||
session->encryptionMode = mode;
|
||||
}
|
||||
|
||||
/***
|
||||
|
@ -191,6 +192,8 @@ tr_initFull( const char * configDir,
|
|||
|
||||
tr_statsInit( h );
|
||||
|
||||
h->web = tr_webInit( h );
|
||||
|
||||
metainfoLookupRescan( h );
|
||||
|
||||
return h;
|
||||
|
|
|
@ -43,12 +43,6 @@ typedef enum { TR_NET_OK, TR_NET_ERROR, TR_NET_WAIT } tr_tristate_t;
|
|||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
int tr_trackerInfoInit( struct tr_tracker_info * info,
|
||||
const char * address,
|
||||
int address_len );
|
||||
|
||||
void tr_trackerInfoClear( struct tr_tracker_info * info );
|
||||
|
||||
uint8_t* tr_peerIdNew( void );
|
||||
|
||||
const uint8_t* tr_getPeerId( void );
|
||||
|
@ -59,13 +53,6 @@ struct tr_metainfo_lookup
|
|||
char * filename;
|
||||
};
|
||||
|
||||
const char * tr_sessionFindTorrentFile( const tr_handle * h,
|
||||
const char * hashString );
|
||||
|
||||
void tr_sessionSetTorrentFile( tr_handle * h,
|
||||
const char * hashString,
|
||||
const char * filename );
|
||||
|
||||
struct tr_handle
|
||||
{
|
||||
unsigned int isPortSet : 1;
|
||||
|
@ -98,6 +85,8 @@ struct tr_handle
|
|||
|
||||
struct tr_lock * lock;
|
||||
|
||||
struct tr_web * web;
|
||||
|
||||
tr_handle_status stats[2];
|
||||
int statCur;
|
||||
|
||||
|
@ -108,8 +97,17 @@ struct tr_handle
|
|||
int metainfoLookupCount;
|
||||
};
|
||||
|
||||
void tr_globalLock ( struct tr_handle * );
|
||||
void tr_globalUnlock ( struct tr_handle * );
|
||||
int tr_globalIsLocked ( const struct tr_handle * );
|
||||
typedef struct tr_handle tr_session;
|
||||
|
||||
const char * tr_sessionFindTorrentFile( const tr_session * session,
|
||||
const char * hashString );
|
||||
|
||||
void tr_sessionSetTorrentFile( tr_session * session,
|
||||
const char * hashString,
|
||||
const char * filename );
|
||||
|
||||
void tr_globalLock ( tr_session * );
|
||||
void tr_globalUnlock ( tr_session * );
|
||||
int tr_globalIsLocked ( const tr_session * );
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -702,8 +702,7 @@ tr_piece;
|
|||
|
||||
typedef struct tr_tracker_info
|
||||
{
|
||||
char * address;
|
||||
int port;
|
||||
int tier;
|
||||
char * announce;
|
||||
char * scrape;
|
||||
}
|
||||
|
@ -723,14 +722,9 @@ struct tr_info
|
|||
unsigned int isPrivate : 1;
|
||||
unsigned int isMultifile : 1;
|
||||
|
||||
/* Tracker info */
|
||||
struct
|
||||
{
|
||||
tr_tracker_info * list;
|
||||
int count;
|
||||
} * trackerList;
|
||||
int trackerTiers;
|
||||
char * primaryAddress;
|
||||
/* these trackers are sorted by tier */
|
||||
tr_tracker_info * trackers;
|
||||
int trackerCount;
|
||||
|
||||
/* Torrent info */
|
||||
char * comment;
|
||||
|
|
|
@ -190,7 +190,7 @@ tr_eventInit( tr_handle * handle )
|
|||
eh = tr_new0( tr_event_handle, 1 );
|
||||
eh->lock = tr_lockNew( );
|
||||
eh->h = handle;
|
||||
eh->pulseInterval = timevalMsec( 100 );
|
||||
eh->pulseInterval = tr_timevalMsec( 100 );
|
||||
eh->thread = tr_threadNew( libeventThreadFunc, eh, "libeventThreadFunc" );
|
||||
}
|
||||
|
||||
|
@ -289,7 +289,7 @@ tr_timerNew( struct tr_handle * handle,
|
|||
uint64_t timeout_milliseconds )
|
||||
{
|
||||
tr_timer * timer = tr_new0( tr_timer, 1 );
|
||||
timer->tv = timevalMsec( timeout_milliseconds );
|
||||
timer->tv = tr_timevalMsec( timeout_milliseconds );
|
||||
timer->func = func;
|
||||
timer->user_data = user_data;
|
||||
timer->eh = handle->events;
|
||||
|
|
|
@ -43,8 +43,6 @@
|
|||
#include <kernel/OS.h>
|
||||
#endif
|
||||
|
||||
#include <miniupnp/miniwget.h> /* parseURL */
|
||||
|
||||
#include "transmission.h"
|
||||
#include "trcompat.h"
|
||||
#include "utils.h"
|
||||
|
@ -352,7 +350,7 @@ tr_compareUint32( uint32_t a, uint32_t b )
|
|||
**/
|
||||
|
||||
struct timeval
|
||||
timevalMsec( uint64_t milliseconds )
|
||||
tr_timevalMsec( uint64_t milliseconds )
|
||||
{
|
||||
struct timeval ret;
|
||||
const uint64_t microseconds = milliseconds * 1000;
|
||||
|
@ -954,28 +952,67 @@ tr_sha1_to_hex( char * out, const uint8_t * sha1 )
|
|||
****
|
||||
***/
|
||||
|
||||
int
|
||||
tr_httpIsValidURL( const char * url )
|
||||
{
|
||||
return !tr_httpParseURL( url, -1, NULL, NULL, NULL );
|
||||
}
|
||||
|
||||
int
|
||||
tr_httpParseURL( const char * url_in, int len,
|
||||
char ** setme_host,
|
||||
int * setme_port,
|
||||
char ** setme_path )
|
||||
{
|
||||
char * url = tr_strndup( url_in, len );
|
||||
char * path;
|
||||
char host[4096+1];
|
||||
unsigned short port;
|
||||
int success;
|
||||
int err;
|
||||
int port = 0;
|
||||
int n;
|
||||
char * tmp;
|
||||
char * pch;
|
||||
const char * protocol = NULL;
|
||||
const char * host = NULL;
|
||||
const char * path = NULL;
|
||||
|
||||
success = parseURL( url, host, &port, &path );
|
||||
|
||||
if( success ) {
|
||||
if( setme_host ) *setme_host = tr_strdup( host );
|
||||
if( setme_port ) *setme_port = port;
|
||||
if( setme_path ) *setme_path = tr_strdup( path );
|
||||
tmp = tr_strndup( url_in, len );
|
||||
if(( pch = strstr( tmp, "://" )))
|
||||
{
|
||||
*pch = '\0';
|
||||
protocol = tmp;
|
||||
pch += 3;
|
||||
/*fprintf( stderr, "protocol is [%s]... what's left is [%s]\n", protocol, pch );*/
|
||||
if(( n = strcspn( pch, ":/" )))
|
||||
{
|
||||
const int havePort = pch[n] == ':';
|
||||
host = pch;
|
||||
pch += n;
|
||||
*pch++ = '\0';
|
||||
/*fprintf( stderr, "host is [%s]... what's left is [%s]\n", host, pch );*/
|
||||
if( havePort )
|
||||
{
|
||||
char * end;
|
||||
port = strtol( pch, &end, 10 );
|
||||
pch = end;
|
||||
/*fprintf( stderr, "port is [%d]... what's left is [%s]\n", port, pch );*/
|
||||
}
|
||||
path = pch;
|
||||
/*fprintf( stderr, "path is [%s]\n", path );*/
|
||||
}
|
||||
}
|
||||
|
||||
tr_free( url );
|
||||
err = !host || !path || !protocol || ( strcmp(protocol,"http") && strcmp(protocol,"https") );
|
||||
|
||||
return !success;
|
||||
if( !err && !port ) {
|
||||
if( !strcmp(protocol,"http") ) port = 80;
|
||||
if( !strcmp(protocol,"https") ) port = 443;
|
||||
}
|
||||
|
||||
if( !err ) {
|
||||
if( setme_host) { ((char*)host)[-3]=':'; *setme_host = tr_strdup( protocol ); }
|
||||
if( setme_path) { ((char*)path)[-1]='/'; *setme_path = tr_strdup( path-1 ); }
|
||||
if( setme_port) *setme_port = port;
|
||||
}
|
||||
|
||||
|
||||
tr_free( tmp );
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ int tr_asprintf( char **strp, const char *fmt, ...);
|
|||
void tr_buildPath( char* buf, size_t buflen,
|
||||
const char * first_element, ... );
|
||||
|
||||
struct timeval timevalMsec( uint64_t milliseconds );
|
||||
struct timeval tr_timevalMsec( uint64_t milliseconds );
|
||||
|
||||
|
||||
int tr_ioErrorFromErrno( int err );
|
||||
|
@ -160,6 +160,8 @@ int tr_compareUint32( uint32_t a, uint32_t b );
|
|||
void tr_sha1_to_hex( char * out, const uint8_t * sha1 );
|
||||
|
||||
|
||||
int tr_httpIsValidURL( const char * url );
|
||||
|
||||
int tr_httpParseURL( const char * url,
|
||||
int url_len,
|
||||
char ** setme_host,
|
||||
|
|
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
* This file Copyright (C) 2008 Charles Kerr <charles@rebelbase.com>
|
||||
*
|
||||
* This file is licensed by the GPL version 2. Works owned by the
|
||||
* Transmission project are granted a special exemption to clause 2(b)
|
||||
* so that the bulk of its code can remain under the MIT license.
|
||||
* This exemption does not extend to derived works not owned by
|
||||
* the Transmission project.
|
||||
*
|
||||
* $Id:$
|
||||
*/
|
||||
|
||||
#include <event.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "transmission.h"
|
||||
#include "utils.h"
|
||||
#include "web.h"
|
||||
|
||||
struct tr_web
|
||||
{
|
||||
CURLM * cm;
|
||||
tr_session * session;
|
||||
int remain;
|
||||
struct event timeout;
|
||||
};
|
||||
|
||||
struct tr_web_task
|
||||
{
|
||||
unsigned int tag;
|
||||
struct evbuffer * response;
|
||||
tr_web_done_func * done_func;
|
||||
void * done_func_user_data;
|
||||
};
|
||||
|
||||
static size_t
|
||||
writeFunc( void * ptr, size_t size, size_t nmemb, void * vtask )
|
||||
{
|
||||
const size_t byteCount = size * nmemb;
|
||||
struct tr_web_task * task = vtask;
|
||||
evbuffer_add( task->response, ptr, byteCount );
|
||||
return byteCount;
|
||||
}
|
||||
|
||||
void
|
||||
tr_webRun( tr_session * session,
|
||||
const char * url,
|
||||
tr_web_done_func * done_func,
|
||||
void * done_func_user_data )
|
||||
{
|
||||
static unsigned int tag = 0;
|
||||
struct tr_web_task * task;
|
||||
struct tr_web * web = session->web;
|
||||
CURL * ch;
|
||||
CURLMcode rc;
|
||||
|
||||
task = tr_new0( struct tr_web_task, 1 );
|
||||
task->done_func = done_func;
|
||||
task->done_func_user_data = done_func_user_data;
|
||||
task->tag = ++tag;
|
||||
task->response = evbuffer_new( );
|
||||
|
||||
fprintf( stderr, "new web tag %u [%s]\n", task->tag, url );
|
||||
++web->remain;
|
||||
|
||||
ch = curl_easy_init( );
|
||||
curl_easy_setopt( ch, CURLOPT_PRIVATE, task );
|
||||
curl_easy_setopt( ch, CURLOPT_URL, url );
|
||||
curl_easy_setopt( ch, CURLOPT_WRITEFUNCTION, writeFunc );
|
||||
curl_easy_setopt( ch, CURLOPT_WRITEDATA, task );
|
||||
curl_easy_setopt( ch, CURLOPT_USERAGENT, TR_NAME "/" LONG_VERSION_STRING );
|
||||
|
||||
curl_multi_add_handle( web->cm, ch );
|
||||
|
||||
do {
|
||||
int tmp;
|
||||
rc = curl_multi_socket_all( web->cm, &tmp );
|
||||
} while( rc == CURLM_CALL_MULTI_PERFORM );
|
||||
}
|
||||
|
||||
static void
|
||||
responseHandler( tr_web * web )
|
||||
{
|
||||
int remaining = 0;
|
||||
|
||||
do {
|
||||
CURLMsg * msg = curl_multi_info_read( web->cm, &remaining );
|
||||
if( msg && ( msg->msg == CURLMSG_DONE ) )
|
||||
{
|
||||
CURL * ch;
|
||||
struct tr_web_task * task;
|
||||
long response_code;
|
||||
|
||||
if( msg->data.result != CURLE_OK )
|
||||
tr_err( "%s", curl_easy_strerror( msg->data.result ) );
|
||||
|
||||
ch = msg->easy_handle;
|
||||
curl_easy_getinfo( ch, CURLINFO_PRIVATE, &task );
|
||||
curl_easy_getinfo( ch, CURLINFO_RESPONSE_CODE, &response_code );
|
||||
|
||||
fprintf( stderr, "web task %u done\n", task->tag );
|
||||
task->done_func( web->session,
|
||||
response_code,
|
||||
EVBUFFER_DATA(task->response),
|
||||
EVBUFFER_LENGTH(task->response),
|
||||
task->done_func_user_data );
|
||||
|
||||
curl_multi_remove_handle( web->cm, ch );
|
||||
curl_easy_cleanup( ch );
|
||||
|
||||
evbuffer_free( task->response );
|
||||
tr_free( task );
|
||||
}
|
||||
}
|
||||
while( remaining );
|
||||
}
|
||||
|
||||
/* libevent says that sock is ready to be processed, so wake up libcurl */
|
||||
static void
|
||||
event_callback( int sock, short action, void * vweb )
|
||||
{
|
||||
tr_web * web = vweb;
|
||||
CURLMcode rc;
|
||||
int mask;
|
||||
|
||||
#if 0
|
||||
static const char *strings[] = {
|
||||
"NONE","TIMEOUT","READ","TIMEOUT|READ","WRITE","TIMEOUT|WRITE",
|
||||
"READ|WRITE","TIMEOUT|READ|WRITE","SIGNAL" };
|
||||
fprintf( stderr, "Event on socket %d (%s)\n", sock, strings[action] );
|
||||
#endif
|
||||
|
||||
switch (action & (EV_READ|EV_WRITE)) {
|
||||
case EV_READ: mask = CURL_CSELECT_IN; break;
|
||||
case EV_WRITE: mask = CURL_CSELECT_OUT; break;
|
||||
case EV_READ|EV_WRITE: mask = CURL_CSELECT_IN|CURL_CSELECT_OUT; break;
|
||||
default: tr_err( "Unknown event %d\n", (int)action ); return;
|
||||
}
|
||||
|
||||
do
|
||||
rc = curl_multi_socket_action( web->cm, sock, mask, &web->remain );
|
||||
while( rc == CURLM_CALL_MULTI_PERFORM );
|
||||
|
||||
if ( rc != CURLM_OK )
|
||||
tr_err( "%s (%d)", curl_multi_strerror(rc), (int)sock );
|
||||
|
||||
responseHandler( web );
|
||||
|
||||
/* remove timeout if there are no transfers left */
|
||||
if( !web->remain
|
||||
&& event_initialized( &web->timeout )
|
||||
&& event_pending( &web->timeout, EV_TIMEOUT, NULL ) ) {
|
||||
event_del( &web->timeout );
|
||||
fprintf( stderr, "Removed timeout\n" );
|
||||
}
|
||||
}
|
||||
|
||||
/* libcurl wants us to tell it when sock is ready to be processed */
|
||||
static int
|
||||
socket_callback( CURL * easy UNUSED,
|
||||
curl_socket_t sock,
|
||||
int action,
|
||||
void * vweb,
|
||||
void * assigndata )
|
||||
{
|
||||
tr_web * web = vweb;
|
||||
int events = EV_PERSIST;
|
||||
struct event * ev = assigndata;
|
||||
|
||||
if( ev )
|
||||
event_del( ev );
|
||||
else {
|
||||
ev = tr_new0( struct event, 1 );
|
||||
curl_multi_assign( web->cm, sock, ev );
|
||||
}
|
||||
|
||||
#if 0
|
||||
{
|
||||
static const char *actions[] = {"NONE", "IN", "OUT", "INOUT", "REMOVE"};
|
||||
fprintf( stderr, "Callback on socket %d (%s)\n", (int)sock, actions[action]);
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (action) {
|
||||
case CURL_POLL_IN: events |= EV_READ; break;
|
||||
case CURL_POLL_OUT: events |= EV_WRITE; break;
|
||||
case CURL_POLL_INOUT: events |= EV_READ|EV_WRITE; break;
|
||||
case CURL_POLL_REMOVE: tr_free( ev ); /* fallthrough */
|
||||
case CURL_POLL_NONE: return 0;
|
||||
default: tr_err( "Unknown socket action %d", action ); return -1;
|
||||
}
|
||||
|
||||
event_set( ev, sock, events, event_callback, web );
|
||||
event_add( ev, NULL );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* libevent says that timeout_ms have passed, so wake up libcurl */
|
||||
static void
|
||||
timeout_callback( int socket UNUSED, short action UNUSED, void * vweb )
|
||||
{
|
||||
CURLMcode rc;
|
||||
tr_web * web = vweb;
|
||||
|
||||
do
|
||||
rc = curl_multi_socket( web->cm, CURL_SOCKET_TIMEOUT, &web->remain );
|
||||
while( rc == CURLM_CALL_MULTI_PERFORM );
|
||||
|
||||
if( rc != CURLM_OK )
|
||||
tr_err( "%s", curl_multi_strerror( rc ) );
|
||||
}
|
||||
|
||||
/* libcurl wants us to tell it when timeout_ms have passed */
|
||||
static void
|
||||
timer_callback( CURLM *multi UNUSED, long timeout_ms, void * vweb )
|
||||
{
|
||||
tr_web * web = vweb;
|
||||
struct timeval tv = tr_timevalMsec( timeout_ms );
|
||||
|
||||
if( event_initialized( &web->timeout )
|
||||
&& event_pending( &web->timeout, EV_TIMEOUT, NULL ) )
|
||||
event_del( &web->timeout );
|
||||
|
||||
event_set( &web->timeout, -1, 0, timeout_callback, vweb );
|
||||
event_add( &web->timeout, &tv );
|
||||
}
|
||||
|
||||
tr_web*
|
||||
tr_webInit( tr_session * session )
|
||||
{
|
||||
static int curlInited = FALSE;
|
||||
tr_web * web;
|
||||
|
||||
/* call curl_global_init if we haven't done it already.
|
||||
* try to enable ssl for https support; but if that fails,
|
||||
* try a plain vanilla init */
|
||||
if( curlInited == FALSE ) {
|
||||
curlInited = TRUE;
|
||||
if( curl_global_init( CURL_GLOBAL_SSL ) )
|
||||
curl_global_init( 0 );
|
||||
}
|
||||
|
||||
web = tr_new0( struct tr_web, 1 );
|
||||
web->cm = curl_multi_init( );
|
||||
web->session = session;
|
||||
web->remain = 0;
|
||||
|
||||
curl_multi_setopt( web->cm, CURLMOPT_SOCKETDATA, web );
|
||||
curl_multi_setopt( web->cm, CURLMOPT_SOCKETFUNCTION, socket_callback );
|
||||
curl_multi_setopt( web->cm, CURLMOPT_TIMERDATA, web );
|
||||
curl_multi_setopt( web->cm, CURLMOPT_TIMERFUNCTION, timer_callback );
|
||||
curl_multi_setopt( web->cm, CURLMOPT_MAXCONNECTS, 20 );
|
||||
curl_multi_setopt( web->cm, CURLMOPT_PIPELINING, 1 );
|
||||
|
||||
return web;
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* This file Copyright (C) 2008 Charles Kerr <charles@rebelbase.com>
|
||||
*
|
||||
* This file is licensed by the GPL version 2. Works owned by the
|
||||
* Transmission project are granted a special exemption to clause 2(b)
|
||||
* so that the bulk of its code can remain under the MIT license.
|
||||
* This exemption does not extend to derived works not owned by
|
||||
* the Transmission project.
|
||||
*
|
||||
* $Id:$
|
||||
*/
|
||||
|
||||
#ifndef TR_HTTP_H
|
||||
#define TR_HTTP_H
|
||||
|
||||
struct tr_handle;
|
||||
typedef struct tr_web tr_web;
|
||||
|
||||
tr_web* tr_webInit( tr_handle * session );
|
||||
|
||||
typedef void (tr_web_done_func)( tr_handle * session,
|
||||
long response_code,
|
||||
const void * response,
|
||||
size_t response_byte_count,
|
||||
void * user_data );
|
||||
|
||||
void tr_webRun( tr_handle * session,
|
||||
const char * url,
|
||||
tr_web_done_func done_func,
|
||||
void * done_func_user_data );
|
||||
|
||||
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue