(gtk) use libT's curl wrapper for port testing & getting the blocklist

This commit is contained in:
Charles Kerr 2008-04-25 18:35:48 +00:00
parent c46269805d
commit 0545e70f5b
2 changed files with 140 additions and 126 deletions

View File

@ -14,9 +14,9 @@
#include <unistd.h>
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <third-party/miniupnp/miniwget.h>
#include <libtransmission/transmission.h>
#include <libtransmission/utils.h>
#include <libtransmission/web.h>
#include "conf.h"
#include "hig.h"
#include "tr-core.h"
@ -177,46 +177,48 @@ struct test_port_data
gboolean * alive;
};
static gpointer
test_port( gpointer data_gpointer )
static void
testing_port_done( tr_handle * handle UNUSED,
long response_code UNUSED,
const void * response,
size_t response_len,
void * gdata )
{
struct test_port_data * data = data_gpointer;
struct test_port_data * data = gdata;
if( *data->alive )
{
GObject * o = G_OBJECT( data->label );
GtkSpinButton * spin = g_object_get_data( o, "tr-port-spin" );
const int port = gtk_spin_button_get_value_as_int( spin );
int isOpen;
int size;
char * text;
char url[256];
g_usleep( G_USEC_PER_SEC * 3 ); /* give portmapping time to kick in */
snprintf( url, sizeof(url), "http://portcheck.transmissionbt.com/%d", port );
text = miniwget( url, &size );
/*g_message(" got len %d, [%*.*s]", size, size, size, text );*/
isOpen = text && *text=='1';
free( text );
if( *data->alive )
gtk_label_set_markup( GTK_LABEL(data->label), isOpen
? _("Port is <b>open</b>")
: _("Port is <b>closed</b>") );
const int isOpen = response_len && *(char*)response=='1';
gtk_label_set_markup( GTK_LABEL( data->label ), isOpen
? _("Port is <b>open</b>")
: _("Port is <b>closed</b>") );
}
}
g_free( data );
return NULL;
static gboolean
testing_port_begin( gpointer gdata )
{
struct test_port_data * data = gdata;
if( *data->alive )
{
GtkSpinButton * spin = g_object_get_data( G_OBJECT( data->label ), "tr-port-spin" );
tr_handle * handle = g_object_get_data( G_OBJECT( data->label ), "handle" );
const int port = gtk_spin_button_get_value_as_int( spin );
char url[256];
snprintf( url, sizeof(url), "http://portcheck.transmissionbt.com/%d", port );
gtk_label_set_markup( GTK_LABEL( data->label ), _( "<i>Testing port...</i>" ) );
tr_webRun( handle, url, testing_port_done, data );
}
return FALSE;
}
static void
testing_port_cb( GtkWidget * unused UNUSED, gpointer l )
{
/* wait three seconds to give the port forwarding time to kick in */
struct test_port_data * data = g_new0( struct test_port_data, 1 );
data->alive = g_object_get_data( G_OBJECT( l ), "alive" );
data->label = l;
gtk_label_set_markup( GTK_LABEL(l), _( "<i>Testing port...</i>" ) );
g_thread_create( test_port, data, FALSE, NULL );
data->alive = g_object_get_data( G_OBJECT( l ), "alive" );
g_timeout_add( 3000, testing_port_begin, data );
}
static void
@ -316,35 +318,30 @@ blocklistDialogAllowClose( gpointer dialog )
return FALSE;
}
static gpointer
updateBlocklist( gpointer vdata )
static void
got_blocklist( tr_handle * handle UNUSED,
long response_code UNUSED,
const void * response,
size_t response_len,
void * gdata )
{
struct blocklist_data * data = vdata;
int size = 0;
struct blocklist_data * data = gdata;
const char * text = response;
int size = response_len;
int rules = 0;
const char * url;
char * text = NULL;
gchar * filename = NULL;
gchar * filename2 = NULL;
int fd = -1;
int ok = 1;
url = "http://download.m0k.org/transmission/files/level1.gz";
if( ok && !data->abortFlag )
if( !data->abortFlag && ( !text || !size ) )
{
ok = FALSE;
g_snprintf( data->secondary, sizeof( data->secondary ),
_( "Retrieving blocklist..." ) );
_( "Unable to get blocklist." ) );
g_message( data->secondary );
g_idle_add( blocklistDialogSetSecondary, data );
text = miniwget( url, &size );
if( !data->abortFlag && ( !text || !size ) ) {
ok = FALSE;
g_snprintf( data->secondary, sizeof( data->secondary ),
_( "Unable to get blocklist." ) );
g_message( data->secondary );
g_idle_add( blocklistDialogSetSecondary, data );
}
}
}
if( ok && !data->abortFlag )
{
@ -389,7 +386,6 @@ updateBlocklist( gpointer vdata )
g_idle_add( updateBlocklistTextFromData, data );
}
free( text );
/* g_free( data ); */
if( filename2 ) {
unlink( filename2 );
@ -399,7 +395,6 @@ updateBlocklist( gpointer vdata )
unlink( filename );
g_free( filename );
}
return NULL;
}
static void
@ -419,12 +414,16 @@ onUpdateBlocklistCB( GtkButton * w, gpointer gdata )
{
GtkWidget * d;
struct blocklist_data * data = gdata;
tr_handle * handle = g_object_get_data( G_OBJECT( w ), "handle" );
const char * url = "http://download.m0k.org/transmission/files/level1.gz";
d = gtk_message_dialog_new( GTK_WINDOW( gtk_widget_get_toplevel( GTK_WIDGET( w ) ) ),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_INFO,
GTK_BUTTONS_NONE,
_( "Updating Blocklist" ) );
gtk_message_dialog_format_secondary_text( GTK_MESSAGE_DIALOG( d ),
_( "Retrieving blocklist..." ) );
gtk_dialog_add_buttons( GTK_DIALOG( d ),
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
@ -435,7 +434,8 @@ onUpdateBlocklistCB( GtkButton * w, gpointer gdata )
g_signal_connect( d, "response", G_CALLBACK(onUpdateBlocklistResponseCB), data );
gtk_widget_show( d );
g_thread_create( updateBlocklist, data, FALSE, NULL );
tr_webRun( handle, url, got_blocklist, data );
}
static GtkWidget*
@ -462,6 +462,7 @@ peerPage( GObject * core )
data->core = TR_CORE( core );
data->check = w;
g_object_set_data( G_OBJECT( b ), "handle", tr_core_handle( TR_CORE( core ) ) );
g_signal_connect( b, "clicked", G_CALLBACK(onUpdateBlocklistCB), data );
gtk_box_pack_start( GTK_BOX(h), b, FALSE, FALSE, 0 );
g_signal_connect( w, "toggled", G_CALLBACK(target_cb), b );
@ -533,6 +534,7 @@ networkPage( GObject * core, gpointer alive )
g_object_set_data( G_OBJECT(l), "tr-port-spin", w2 );
g_object_set_data( G_OBJECT(l), "alive", alive );
g_object_set_data( G_OBJECT(l), "handle", tr_core_handle( TR_CORE( core ) ) );
testing_port_cb( NULL, l );
g_signal_connect( w, "toggled", G_CALLBACK(testing_port_cb), l );

View File

@ -1,4 +1,5 @@
/* * This file Copyright (C) 2008 Charles Kerr <charles@rebelbase.com>
/*
* 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)
@ -15,6 +16,7 @@
#include <curl/curl.h>
#include "transmission.h"
#include "trevent.h"
#include "utils.h"
#include "web.h"
@ -28,9 +30,7 @@
#define USE_CURL_MULTI_SOCKET
#else
#define PULSE_MSEC 200
static void pulse( int socket UNUSED, short action UNUSED, void * vweb );
#endif
static void processCompletedTasks( tr_web * );
#define dbgmsg(fmt...) tr_deepLog( __FILE__, __LINE__, "web", ##fmt )
@ -46,80 +46,24 @@ struct tr_web_task
{
unsigned long tag;
struct evbuffer * response;
char * url;
tr_session * session;
tr_web_done_func * done_func;
void * done_func_user_data;
};
static size_t
writeFunc( void * ptr, size_t size, size_t nmemb, void * task )
{
const size_t byteCount = size * nmemb;
evbuffer_add( ((struct tr_web_task*)task)->response, ptr, byteCount );
return byteCount;
}
static void
pump( tr_web * web )
{
int unused;
CURLMcode rc;
do
#ifdef USE_CURL_MULTI_SOCKET
rc = curl_multi_socket_all( web->cm, &unused );
#else
rc = curl_multi_perform( web->cm, &unused );
#endif
while( rc == CURLM_CALL_MULTI_PERFORM );
if ( rc == CURLM_OK )
processCompletedTasks( web );
else
tr_err( "%s", curl_multi_strerror(rc) );
}
void
tr_webRun( tr_session * session,
const char * url,
tr_web_done_func * done_func,
void * done_func_user_data )
{
static unsigned long tag = 0;
struct tr_web_task * task;
struct tr_web * web = session->web;
CURL * ch;
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( );
dbgmsg( "adding task #%lu [%s]", 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_easy_setopt( ch, CURLOPT_SSL_VERIFYPEER, 0 );
curl_multi_add_handle( web->cm, ch );
pump( web );
}
static void
processCompletedTasks( tr_web * web )
{
int more = 0;
CURL * easy;
CURLMsg * msg;
CURLcode res;
do {
/* find a completed task. this idea is from the "hiperinfo.c"
* sample that questions the safety of removing an easy handle
* inside the curl_multi_info_read loop */
/* this convoluted loop is from the "hiperinfo.c" sample which
* hints that removing an easy handle in curl_multi_info_read's
* loop may be unsafe */
int more;
easy = NULL;
while(( msg = curl_multi_info_read( web->cm, &more ))) {
if( msg->msg == CURLMSG_DONE ) {
@ -133,9 +77,8 @@ processCompletedTasks( tr_web * web )
int response_code;
curl_easy_getinfo( easy, CURLINFO_PRIVATE, &task );
curl_easy_getinfo( easy, CURLINFO_RESPONSE_CODE, &response_code );
--web->remain;
dbgmsg( "task #%lu done (%d tasks remain)", task->tag, web->remain );
dbgmsg( "task #%lu done (%d remain)", task->tag, web->remain );
task->done_func( web->session,
response_code,
EVBUFFER_DATA(task->response),
@ -145,16 +88,85 @@ processCompletedTasks( tr_web * web )
curl_multi_remove_handle( web->cm, easy );
curl_easy_cleanup( easy );
evbuffer_free( task->response );
tr_free( task->url );
tr_free( task );
}
} while( easy );
}
static void
pump( tr_web * web )
{
int unused;
CURLMcode rc;
do {
#ifdef USE_CURL_MULTI_SOCKET
rc = curl_multi_socket_all( web->cm, &unused );
#else
rc = curl_multi_perform( web->cm, &unused );
#endif
} while( rc == CURLM_CALL_MULTI_PERFORM );
if ( rc == CURLM_OK )
processCompletedTasks( web );
else
tr_err( "%s", curl_multi_strerror(rc) );
}
static size_t
writeFunc( void * ptr, size_t size, size_t nmemb, void * task )
{
const size_t byteCount = size * nmemb;
evbuffer_add( ((struct tr_web_task*)task)->response, ptr, byteCount );
return byteCount;
}
static void
addTask( void * vtask )
{
struct tr_web_task * task = vtask;
struct tr_web * web = task->session->web;
CURL * ch;
dbgmsg( "adding task #%lu [%s]", task->tag, task->url );
++web->remain;
ch = curl_easy_init( );
curl_easy_setopt( ch, CURLOPT_PRIVATE, task );
curl_easy_setopt( ch, CURLOPT_URL, task->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_easy_setopt( ch, CURLOPT_SSL_VERIFYPEER, 0 );
curl_multi_add_handle( web->cm, ch );
pump( web );
}
void
tr_webRun( tr_session * session,
const char * url,
tr_web_done_func * done_func,
void * done_func_user_data )
{
static unsigned long tag = 0;
struct tr_web_task * task;
task = tr_new0( struct tr_web_task, 1 );
task->session = session;
task->url = tr_strdup( url );
task->done_func = done_func;
task->done_func_user_data = done_func_user_data;
task->tag = ++tag;
task->response = evbuffer_new( );
tr_runInEventThread( session, addTask, task );
}
#ifdef USE_CURL_MULTI_SOCKET
/* libevent says that sock is ready to be processed, so tell libcurl */
static void
event_callback( int sock, short action, void * vweb )
ev_sock_cb( int sock, short action, void * vweb )
{
tr_web * web = vweb;
CURLMcode rc;
@ -167,13 +179,14 @@ event_callback( int sock, short action, void * vweb )
default: tr_err( "Unknown event %hd\n", action ); return;
}
do rc = curl_multi_socket_action( web->cm, sock, mask, &unused );
while( rc == CURLM_CALL_MULTI_PERFORM );
if ( rc != CURLM_OK )
do {
rc = curl_multi_socket_action( web->cm, sock, mask, &unused );
} while( rc == CURLM_CALL_MULTI_PERFORM );
if ( rc == CURLM_OK )
processCompletedTasks( web );
else
tr_err( "%s (%d)", curl_multi_strerror(rc), (int)sock );
processCompletedTasks( web );
}
/* CURLMPOPT_SOCKETFUNCTION */
@ -205,7 +218,7 @@ multi_sock_cb( CURL * easy UNUSED,
kind = EV_PERSIST;
if( action & CURL_POLL_IN ) kind |= EV_READ;
if( action & CURL_POLL_OUT ) kind |= EV_WRITE;
event_set( ev, sock, kind, event_callback, web );
event_set( ev, sock, kind, ev_sock_cb, web );
event_add( ev, NULL );
}
}
@ -245,7 +258,6 @@ pulse( int socket UNUSED, short action UNUSED, void * vweb )
struct timeval tv = tr_timevalMsec( PULSE_MSEC );
pump( web );
processCompletedTasks( web );
evtimer_del( &web->timer );
evtimer_add( &web->timer, &tv );