Changeset 864


Ignore:
Timestamp:
Sep 17, 2006, 11:00:51 PM (15 years ago)
Author:
joshe
Message:

Add nat traversal support (ie: NAT-PMP and UPnP)

Location:
branches/nat-traversal
Files:
8 added
27 edited

Legend:

Unmodified
Added
Removed
  • branches/nat-traversal/cli/transmissioncli.1

    r261 r864  
    2727.Op Fl s Ar torrent-file
    2828.Op Fl v Ar level
     29.Op Fl n
    2930.Op Fl p Ar port
    3031.Op Fl u Ar upload-rate
     
    5152Sets debugging options.  The current range is 0-2, with the highest
    5253level producing the most output.  The default is 0.
     54.It Fl n, Fl -nat-traversal
     55Attempt to use the NAT-PMP and UPnP IGD protocols to establish a port
     56mapping for allowing incoming peer connections.
    5357.It Fl p, -port Ar port
    5458Specifies an alternate port for the client to listen on.  The default is
  • branches/nat-traversal/cli/transmissioncli.c

    r310 r864  
    3838"Usage: %s [options] file.torrent [options]\n\n" \
    3939"Options:\n" \
     40"  -d, --download <int> Maximum download rate (-1 = no limit, default = -1)\n"\
     41"  -f, --finish <shell script> Command you wish to run on completion\n" \
    4042"  -h, --help           Print this help and exit\n" \
    4143"  -i, --info           Print metainfo and exit\n" \
     44"  -n  --nat-traversal  Attempt NAT traversal using NAT-PMP or UPnP IGD\n" \
     45"  -p, --port <int>     Port we should listen on (default = %d)\n" \
    4246"  -s, --scrape         Print counts of seeders/leechers and exit\n" \
    43 "  -v, --verbose <int>  Verbose level (0 to 2, default = 0)\n" \
    44 "  -p, --port <int>     Port we should listen on (default = %d)\n" \
    4547"  -u, --upload <int>   Maximum upload rate (-1 = no limit, default = 20)\n" \
    46 "  -d, --download <int> Maximum download rate (-1 = no limit, default = -1)\n" \
    47 "  -f, --finish <shell script> Command you wish to run on completion\n"
     48"  -v, --verbose <int>  Verbose level (0 to 2, default = 0)\n"
    4849
    4950static int           showHelp      = 0;
     
    5657static char          * torrentPath = NULL;
    5758static volatile char mustDie       = 0;
     59static int           natTraversal  = 0;
    5860
    5961static char          * finishCall   = NULL;
     
    6466int main( int argc, char ** argv )
    6567{
    66     int i, error;
     68    int i, error, nat;
    6769    tr_handle_t  * h;
    6870    tr_torrent_t * tor;
     
    164166    tr_setUploadLimit( h, uploadLimit );
    165167    tr_setDownloadLimit( h, downloadLimit );
     168
     169    if( natTraversal )
     170    {
     171        tr_natTraversalEnable( h );
     172    }
     173    else
     174    {
     175        tr_natTraversalDisable( h );
     176    }
    166177   
    167178    tr_torrentSetFolder( tor, "." );
     
    201212        memset( &string[chars], ' ', 79 - chars );
    202213        string[79] = '\0';
    203         fprintf( stderr, "\r%s", string );
     214        //fprintf( stderr, "\r%s", string );
    204215
    205216        if( s->error & TR_ETRACKER )
     
    219230    fprintf( stderr, "\n" );
    220231
    221     /* Try for 5 seconds to notice the tracker that we are leaving */
     232    /* Try for 5 seconds to notify the tracker that we are leaving
     233       and to delete any port mappings for nat traversal */
    222234    tr_torrentStop( tor );
     235    tr_natTraversalDisable( h );
    223236    for( i = 0; i < 10; i++ )
    224237    {
    225238        s = tr_torrentStat( tor );
    226         if( s->status & TR_STATUS_PAUSE )
    227         {
    228             /* The 'stopped' message was sent */
     239        nat = tr_natTraversalStatus( h );
     240        if( s->status & TR_STATUS_PAUSE && TR_NAT_TRAVERSAL_DISABLED == nat )
     241        {
     242            /* The 'stopped' tracker message was sent
     243               and port mappings were deleted */
    229244            break;
    230245        }
     
    254269            { "download", required_argument, NULL, 'd' },
    255270            { "finish",   required_argument, NULL, 'f' },
     271            { "nat-traversal", no_argument,  NULL, 'n' },
    256272            { 0, 0, 0, 0} };
    257273
    258274        int c, optind = 0;
    259         c = getopt_long( argc, argv, "hisv:p:u:d:f:", long_options, &optind );
     275        c = getopt_long( argc, argv, "hisv:p:u:d:f:n", long_options, &optind );
    260276        if( c < 0 )
    261277        {
     
    287303            case 'f':
    288304                finishCall = optarg;
     305                break;
     306            case 'n':
     307                natTraversal = 1;
    289308                break;
    290309            default:
  • branches/nat-traversal/gtk/conf.c

    r760 r864  
    359359  GError *err;
    360360  char *datastr;
    361   size_t len;
     361  int len;
    362362  gsize written;
    363363
  • branches/nat-traversal/gtk/conf.h

    r804 r864  
    6060#define PREF_ADDIPC             "add-behavior-ipc"
    6161#define PREF_MSGLEVEL           "message-level"
     62#define PREF_NAT                "use-nat-traversal"
    6263
    6364#endif /* TG_CONF_H */
  • branches/nat-traversal/gtk/dialogs.c

    r804 r864  
    4242#define DEF_UPLIMIT             20
    4343#define DEF_USEUPLIMIT          TRUE
     44#define DEF_NAT                 TRUE
    4445
    4546struct prefdata {
     
    171172   GTK_STOCK_APPLY, GTK_RESPONSE_APPLY, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
    172173   GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
    173   const unsigned int rowcount = 8;
     174  const unsigned int rowcount = 9;
    174175  GtkWidget *table = gtk_table_new(rowcount, 2, FALSE);
    175176  GtkWidget *portnum = gtk_spin_button_new_with_range(1, 0xffff, 1);
     177  GtkWidget *natcheck = gtk_check_button_new_with_mnemonic(
     178    _("Use NAT _Traversal (NAT-PMP and UPnP)"));
    176179  GtkWidget *dirstr = gtk_file_chooser_button_new(
    177180    _("Choose a download directory"),
     
    197200  GtkTreeIter iter;
    198201  GtkCellRenderer *rend;
     202  gboolean boolval;
     203  int intval;
    199204
    200205  g_free(title);
     
    207212
    208213  data->prefwidgets = makeglist(portnum, lim[0].on, lim[0].num, lim[1].on,
    209     lim[1].num, dirstr, addstd, addipc, NULL);
     214    lim[1].num, dirstr, addstd, addipc, natcheck, NULL);
    210215  data->parent = parent;
    211216  data->back = back;
     
    252257  gtk_table_attach_defaults(GTK_TABLE(table), label,           0, 1, RN(ii));
    253258  gtk_table_attach_defaults(GTK_TABLE(table), portnum,         1, 2, RN(ii));
     259  ii++;
     260
     261  /* NAT traversal checkbox */
     262  intval = tr_natTraversalStatus(tr_backend_handle(back));
     263  boolval = !TR_NAT_TRAVERSAL_IS_DISABLED( intval );
     264  setupprefwidget(natcheck, PREF_NAT, boolval);
     265  gtk_table_attach_defaults(GTK_TABLE(table), natcheck,        0, 2, RN(ii));
    254266  ii++;
    255267
     
    341353    }
    342354
     355    applyprefs(data->back);
    343356    /* XXX would be nice to have errno strings, are they printed to stdout? */
    344 
    345     tr_setBindPort(tr_backend_handle(data->back),
    346                    strtol(cf_getpref(PREF_PORT), NULL, 10));
    347     setlimit(data->back);
    348357  }
    349358
     
    353362
    354363void
    355 setlimit(TrBackend *back) {
     364applyprefs(TrBackend *back) {
    356365  struct { void (*func)(tr_handle_t*, int);
    357366    const char *use; const char *num; gboolean defuse; long def; } lim[] = {
     
    362371  };
    363372  const char *pref;
    364   unsigned int ii;
     373  int ii;
    365374  tr_handle_t *tr = tr_backend_handle(back);
    366 
    367   for(ii = 0; ii < ALEN(lim); ii++) {
     375  gboolean boolval;
     376
     377  /* set upload and download limits */
     378  for(ii = 0; ii < (int)ALEN(lim); ii++) {
    368379    pref = cf_getpref(lim[ii].use);
    369380    if(!(NULL == pref ? lim[ii].defuse : strbool(pref)))
     
    374385    }
    375386  }
     387
     388  /* set the listening port */
     389  if(NULL != (pref = cf_getpref(PREF_PORT)) &&
     390     0 < (ii = strtol(pref, NULL, 10)) && 0xffff >= ii)
     391    tr_setBindPort(tr, ii);
     392
     393  /* enable/disable NAT traversal */
     394  boolval = (NULL == (pref = cf_getpref(PREF_NAT)) ? DEF_NAT : strbool(pref));
     395  if( boolval )
     396    tr_natTraversalEnable(tr);
     397  else
     398    tr_natTraversalDisable(tr);
    376399}
    377400
  • branches/nat-traversal/gtk/dialogs.h

    r804 r864  
    3333makeprefwindow(GtkWindow *parent, TrBackend *back);
    3434
    35 /* set the upload limit based on saved prefs */
     35/* set various things based on saved prefs */
    3636void
    37 setlimit(TrBackend *back);
     37applyprefs(TrBackend *back);
    3838
    3939/* show the "add a torrent" dialog */
  • branches/nat-traversal/gtk/ipc.c

    r760 r864  
    264264send_msg(struct constate *con, const char *name, benc_val_t *val) {
    265265  char *buf;
    266   size_t used, total;
     266  int used, total;
    267267  benc_val_t dict;
    268268  char stupid;
  • branches/nat-traversal/gtk/main.c

    r815 r864  
    178178  TrBackend *back;
    179179  benc_val_t *state;
    180   const char *pref;
    181   long intval;
    182180  GList *argfiles;
    183181  gboolean didinit, didlock;
     
    234232      back = tr_backend_new();
    235233
    236       /* set the upload limit */
    237       setlimit(back);
    238 
    239       /* set the listening port */
    240       if(NULL != (pref = cf_getpref(PREF_PORT)) &&
    241          0 < (intval = strtol(pref, NULL, 10)) && 0xffff >= intval)
    242         tr_setBindPort(tr_backend_handle(back), intval);
     234      /* apply a few prefs */
     235      applyprefs(back);
    243236
    244237      makewind(mainwind, back, state, argfiles);
     
    524517  tr_backend_stop_torrents(data->back);
    525518
     519  /* shut down nat traversal */
     520  tr_natTraversalDisable(tr_backend_handle(data->back));
     521
    526522  /* set things up to wait for torrents to stop */
    527523  edata = g_new0(struct exitdata, 1);
     
    545541exitcheck(gpointer gdata) {
    546542  struct exitdata *data = gdata;
    547 
    548   /* keep going if we still have torrents and haven't hit the exit timeout */
     543  int natstat = tr_natTraversalStatus(tr_backend_handle(data->cbdata->back));
     544
     545  /* keep going if we haven't hit the exit timeout and
     546     we either have torrents left or nat traversal is stopping */
    549547  if(time(NULL) - data->started < TRACKER_EXIT_TIMEOUT &&
    550      !tr_backend_torrents_stopped(data->cbdata->back)) {
     548     !tr_backend_torrents_stopped(data->cbdata->back) &&
     549     TR_NAT_TRAVERSAL_DISABLED != natstat) {
    551550    updatemodel(data->cbdata);
    552551    return TRUE;
  • branches/nat-traversal/libtransmission/bencode.c

    r543 r864  
    2626
    2727#define LIST_SIZE   20
    28 #define OUTBUF_SIZE 100
    29 
    30 static int tr_bencSprintf( char ** buf, size_t * used, size_t * max,
    31                            char * format, ... )
    32 #ifdef __GNUC__
    33     __attribute__ ((format (printf, 4, 5)))
    34 #endif
    35     ;
    36 
    37 int _tr_bencLoad( char * buf, size_t len, benc_val_t * val, char ** end )
     28
     29int _tr_bencLoad( char * buf, int len, benc_val_t * val, char ** end )
    3830{
    3931    char * p, * e, * foo;
     
    9082        cur              = &buf[1];
    9183        str_expected     = 1;
    92         while( (size_t)(cur - buf) < len && cur[0] != 'e' )
     84        while( cur - buf < len && cur[0] != 'e' )
    9385        {
    9486            if( val->val.l.count == val->val.l.alloc )
     
    140132
    141133        if( p != e || 0 > val->val.s.i ||
    142             (size_t)(val->val.s.i) > len - ((p + 1) - buf) )
     134            val->val.s.i > len - ((p + 1) - buf) )
    143135        {
    144136            return 1;
     
    241233}
    242234
    243 char * tr_bencSaveMalloc( benc_val_t * val, size_t * len )
     235char * tr_bencSaveMalloc( benc_val_t * val, int * len )
    244236{
    245237    char * buf   = NULL;
    246     size_t alloc = 0;
     238    int alloc = 0;
    247239
    248240    *len = 0;
     
    260252}
    261253
    262 int tr_bencSave( benc_val_t * val, char ** buf, size_t * used, size_t * max )
     254int tr_bencSave( benc_val_t * val, char ** buf, int * used, int * max )
    263255{
    264256    int ii;   
     
    267259    {
    268260        case TYPE_INT:
    269             if( tr_bencSprintf( buf, used, max, "i%"PRIu64"e", val->val.i ) )
     261            if( tr_sprintf( buf, used, max, "i%"PRIu64"e", val->val.i ) )
    270262            {
    271263                return 1;
     
    278270                return 1;
    279271            }
    280             if( tr_bencSprintf( buf, used, max, "%i:%s",
    281                                 val->val.s.i, val->val.s.s ) )
     272            if( tr_sprintf( buf, used, max, "%i:%s",
     273                            val->val.s.i, val->val.s.s ) )
    282274            {
    283275                return 1;
     
    287279        case TYPE_LIST:
    288280        case TYPE_DICT:
    289             if( tr_bencSprintf( buf, used, max,
    290                                 (TYPE_LIST == val->type ? "l" : "d") ) )
     281            if( tr_sprintf( buf, used, max,
     282                            (TYPE_LIST == val->type ? "l" : "d") ) )
    291283            {
    292284                return 1;
     
    299291                }
    300292            }
    301             if( tr_bencSprintf( buf, used, max, "e" ) )
     293            if( tr_sprintf( buf, used, max, "e" ) )
    302294            {
    303295                return 1;
     
    308300    return 0;
    309301}
    310 
    311 static int tr_bencSprintf( char ** buf, size_t * used, size_t * max,
    312                            char * format, ... )
    313 {
    314     va_list ap;
    315     int     want;
    316     char  * newbuf;
    317 
    318     va_start( ap, format );
    319     want = vsnprintf( NULL, 0, format, ap );
    320     va_end(ap);
    321 
    322     while( *used + want + 1 > *max )
    323     {
    324         *max += OUTBUF_SIZE;
    325         newbuf = realloc( *buf, *max );
    326         if( NULL == newbuf )
    327         {
    328             return 1;
    329         }
    330         *buf = newbuf;
    331     }
    332 
    333     va_start( ap, format );
    334     *used += vsnprintf( *buf + *used, *max - *used, format, ap );
    335     va_end( ap );
    336 
    337     return 0;
    338 }
  • branches/nat-traversal/libtransmission/bencode.h

    r261 r864  
    5353
    5454#define tr_bencLoad(b,l,v,e) _tr_bencLoad((char*)(b),(l),(v),(char**)(e))
    55 int          _tr_bencLoad( char * buf, size_t len, benc_val_t * val,
     55int          _tr_bencLoad( char * buf, int len, benc_val_t * val,
    5656                           char ** end );
    5757void         tr_bencPrint( benc_val_t * val );
    5858void         tr_bencFree( benc_val_t * val );
    5959benc_val_t * tr_bencDictFind( benc_val_t * val, char * key );
    60 char *       tr_bencSaveMalloc( benc_val_t * val, size_t * len );
     60char *       tr_bencSaveMalloc( benc_val_t * val, int * len );
    6161int          tr_bencSave( benc_val_t * val, char ** buf,
    62                           size_t * used, size_t * max );
     62                          int * used, int * max );
    6363
    6464#endif
  • branches/nat-traversal/libtransmission/fastresume.h

    r326 r864  
    249249    {
    250250        tr_inf( "Wrong size for resume file (%d bytes, %d expected)",
    251                 ftell( file ), size );
     251                (int)ftell( file ), size );
    252252        fclose( file );
    253253        return 1;
  • branches/nat-traversal/libtransmission/inout.c

    r723 r864  
    417417    {
    418418        /* Should not happen */
    419         tr_err( "readOrWriteBytes: offset out of range (%lld, %d, %d)",
     419        tr_err( "readOrWriteBytes: offset out of range (%"PRIu64", %d, %d)",
    420420                offset, size, isWrite );
    421421        goto fail;
  • branches/nat-traversal/libtransmission/internal.h

    r788 r864  
    2929   That is probably ugly to put them all here, but it is sooo
    3030   convenient */
     31#if ( defined( __unix__ ) || defined( unix ) ) && !defined( USG )
     32#include <sys/param.h>
     33#endif
    3134#include <stdio.h>
    3235#include <stdarg.h>
     
    5154#ifdef BEOS_NETSERVER
    5255#  define in_port_t uint16_t
     56#  define socklen_t uint32_t
    5357#else
    5458#  include <arpa/inet.h>
    5559#endif
    5660
     61#ifndef INADDR_NONE
     62#define INADDR_NONE             0xffffffff
     63#endif
     64
    5765#ifdef __GNUC__
    5866#  define UNUSED __attribute__((unused))
     67#  define PRINTF( fmt, args ) __attribute__((format (printf, fmt, args)))
    5968#else
    6069#  define UNUSED
     70#  define PRINTF( fmt, args )
    6171#endif
    6272
     
    108118typedef struct tr_completion_s tr_completion_t;
    109119
     120typedef enum { TR_OK, TR_ERROR, TR_WAIT } tr_tristate_t;
     121
    110122#include "platform.h"
    111123#include "bencode.h"
     
    119131#include "clients.h"
    120132#include "choking.h"
     133#include "natpmp.h"
     134#include "upnp.h"
     135#include "http.h"
     136#include "xml.h"
    121137
    122138struct tr_torrent_s
     
    188204    tr_fd_t      * fdlimit;
    189205    tr_choking_t * choking;
     206    tr_natpmp_t  * natpmp;
     207    tr_upnp_t    * upnp;
    190208
    191209    int            bindPort;
  • branches/nat-traversal/libtransmission/metainfo.c

    r786 r864  
    7070    if( sb.st_size > TORRENT_MAX_SIZE )
    7171    {
    72         tr_err( "Torrent file is too big (%d bytes)", sb.st_size );
     72        tr_err( "Torrent file is too big (%d bytes)", (int)sb.st_size );
    7373        return 1;
    7474    }
  • branches/nat-traversal/libtransmission/net.c

    r791 r864  
    3636 * Returns a non-zero value if an error occurs.
    3737 **********************************************************************/
    38 int tr_netResolve( char * address, struct in_addr * addr )
     38int tr_netResolve( const char * address, struct in_addr * addr )
    3939{
    4040    addr->s_addr = inet_addr( address );
     
    5353struct tr_resolve_s
    5454{
    55     int            status;
     55    tr_tristate_t  status;
    5656    char           * address;
    5757    struct in_addr addr;
     
    9595 * Adds an address to the resolution queue.
    9696 **********************************************************************/
    97 tr_resolve_t * tr_netResolveInit( char * address )
     97tr_resolve_t * tr_netResolveInit( const char * address )
    9898{
    9999    tr_resolve_t * r;
    100100
    101101    r           = malloc( sizeof( tr_resolve_t ) );
    102     r->status   = TR_RESOLVE_WAIT;
     102    r->status   = TR_WAIT;
    103103    r->address  = strdup( address );
    104104    r->refcount = 2;
     
    126126 * Checks the current status of a resolution.
    127127 **********************************************************************/
    128 int tr_netResolvePulse( tr_resolve_t * r, struct in_addr * addr )
    129 {
    130     int ret;
     128tr_tristate_t tr_netResolvePulse( tr_resolve_t * r, struct in_addr * addr )
     129{
     130    tr_tristate_t ret;
    131131
    132132    tr_lockLock( &resolveLock );
    133133    ret = r->status;
    134     if( ret == TR_RESOLVE_OK )
     134    if( ret == TR_OK )
    135135    {
    136136        *addr = r->addr;
     
    202202        {
    203203            memcpy( &r->addr, host->h_addr, host->h_length );
    204             r->status = TR_RESOLVE_OK;
     204            r->status = TR_OK;
    205205        }
    206206        else
    207207        {
    208             r->status = TR_RESOLVE_ERROR;
     208            r->status = TR_ERROR;
    209209        }
    210210       
     
    252252}
    253253
    254 static int createSocket()
     254static int createSocket( int type )
    255255{
    256256    int s;
    257257
    258     s = socket( AF_INET, SOCK_STREAM, 0 );
     258    s = socket( AF_INET, type, 0 );
    259259    if( s < 0 )
    260260    {
     
    266266}
    267267
    268 int tr_netOpen( struct in_addr addr, in_port_t port )
     268int tr_netOpen( struct in_addr addr, in_port_t port, int type )
    269269{
    270270    int s;
    271271    struct sockaddr_in sock;
    272272
    273     s = createSocket();
     273    s = createSocket( type );
    274274    if( s < 0 )
    275275    {
     
    294294}
    295295
    296 int tr_netBind( int port )
     296#ifdef IP_ADD_MEMBERSHIP
     297int tr_netMcastOpen( int port, struct in_addr addr )
     298{
     299    int fd;
     300    struct ip_mreq req;
     301
     302    fd = tr_netBindUDP( port );
     303    if( 0 > fd )
     304    {
     305        return -1;
     306    }
     307
     308    memset( &req, 0, sizeof( req ) );
     309    req.imr_multiaddr.s_addr = addr.s_addr;
     310    req.imr_interface.s_addr = htonl( INADDR_ANY );
     311    if( setsockopt( fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &req, sizeof ( req ) ) )
     312    {
     313        tr_err( "Could not join multicast group (%s)", strerror( errno ) );
     314        tr_netClose( fd );
     315        return -1;
     316    }
     317
     318    return fd;
     319}
     320#else /* IP_ADD_MEMBERSHIP */
     321int tr_netMcastOpen( int port UNUSED, struct in_addr addr UNUSED )
     322{
     323    return -1;
     324}
     325#endif /* IP_ADD_MEMBERSHIP */
     326
     327int tr_netBind( int port, int type )
    297328{
    298329    int s;
    299330    struct sockaddr_in sock;
    300 #ifdef SO_REUSEADDR
     331#if defined( SO_REUSEADDR ) || defined( SO_REUSEPORT )
    301332    int optval;
    302333#endif
    303334
    304     s = createSocket();
     335    s = createSocket( type );
    305336    if( s < 0 )
    306337    {
     
    313344#endif
    314345
     346#ifdef SO_REUSEPORT
     347    if( SOCK_DGRAM == type )
     348    {
     349        optval = 1;
     350        setsockopt( s, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof( optval ) );
     351    }
     352#endif
     353
    315354    memset( &sock, 0, sizeof( sock ) );
    316355    sock.sin_family      = AF_INET;
     
    325364        return -1;
    326365    }
    327    
    328     tr_inf( "Binded port %d", port );
    329     listen( s, 5 );
    330366
    331367    return s;
     
    372408}
    373409
    374 int tr_netRecv( int s, uint8_t * buf, int size )
    375 {
    376     int ret;
    377 
    378     ret = recv( s, buf, size, 0 );
     410int tr_netRecvFrom( int s, uint8_t * buf, int size, struct sockaddr_in * addr )
     411{
     412    socklen_t len;
     413    int       ret;
     414
     415    len = ( NULL == addr ? 0 : sizeof( *addr ) );
     416    ret = recvfrom( s, buf, size, 0, ( struct sockaddr * ) addr, &len );
    379417    if( ret < 0 )
    380418    {
  • branches/nat-traversal/libtransmission/net.h

    r791 r864  
    2727 * DNS resolution
    2828 **********************************************************************/
    29 int tr_netResolve( char *, struct in_addr * );
     29int tr_netResolve( const char *, struct in_addr * );
    3030
    31 #define TR_RESOLVE_WAIT  0
    32 #define TR_RESOLVE_ERROR 1
    33 #define TR_RESOLVE_OK    2
    3431typedef struct tr_resolve_s tr_resolve_t;
    3532void           tr_netResolveThreadInit();
    3633void           tr_netResolveThreadClose();
    37 tr_resolve_t * tr_netResolveInit( char * );
    38 int            tr_netResolvePulse( tr_resolve_t *, struct in_addr * );
     34tr_resolve_t * tr_netResolveInit( const char * );
     35tr_tristate_t  tr_netResolvePulse( tr_resolve_t *, struct in_addr * );
    3936void           tr_netResolveClose( tr_resolve_t * );
    4037
     
    4340 * TCP sockets
    4441 **********************************************************************/
    45 int  tr_netOpen    ( struct in_addr addr, in_port_t port );
    46 int  tr_netBind    ( int );
     42#define tr_netOpenTCP( addr, port ) tr_netOpen( (addr), (port), SOCK_STREAM )
     43#define tr_netOpenUDP( addr, port ) tr_netOpen( (addr), (port), SOCK_DGRAM )
     44int  tr_netOpen    ( struct in_addr addr, in_port_t port, int type );
     45int  tr_netMcastOpen( int port, struct in_addr addr );
     46#define tr_netBindTCP( port ) tr_netBind( (port), SOCK_STREAM )
     47#define tr_netBindUDP( port ) tr_netBind( (port), SOCK_DGRAM )
     48int  tr_netBind    ( int port, int type );
    4749int  tr_netAccept  ( int s, struct in_addr *, in_port_t * );
    4850void tr_netClose   ( int s );
     
    5153#define TR_NET_CLOSE 0x40000000
    5254int  tr_netSend    ( int s, uint8_t * buf, int size );
    53 int  tr_netRecv    ( int s, uint8_t * buf, int size );
     55#define tr_netRecv( s, buf, size ) tr_netRecvFrom( (s), (buf), (size), NULL )
     56int  tr_netRecvFrom( int s, uint8_t * buf, int size, struct sockaddr_in * );
    5457
    5558void tr_netNtop( const struct in_addr * addr, char * buf, int len );
  • branches/nat-traversal/libtransmission/peer.c

    r774 r864  
    101101
    102102#define peer_dbg( a... ) __peer_dbg( peer, ## a )
     103static void __peer_dbg( tr_peer_t * peer, char * msg, ... ) PRINTF( 2, 3 );
     104
    103105static void __peer_dbg( tr_peer_t * peer, char * msg, ... )
    104106{
  • branches/nat-traversal/libtransmission/peerutils.h

    r261 r864  
    152152        !tr_fdSocketWillCreate( tor->fdlimit, 0 ) )
    153153    {
    154         peer->socket = tr_netOpen( peer->addr, peer->port );
     154        peer->socket = tr_netOpenTCP( peer->addr, peer->port );
    155155        if( peer->socket < 0 )
    156156        {
  • branches/nat-traversal/libtransmission/platform.c

    r679 r864  
    197197}
    198198
     199#if defined( BSD )
     200
     201#include <sys/sysctl.h>
     202#include <net/route.h>
     203
     204static uint8_t *
     205getroute( int * buflen );
     206static int
     207parseroutes( uint8_t * buf, int len, struct in_addr * addr );
     208
     209int
     210tr_getDefaultRoute( struct in_addr * addr )
     211{
     212    uint8_t * buf;
     213    int len;
     214
     215    buf = getroute( &len );
     216    if( NULL == buf )
     217    {
     218        tr_err( "failed to get default route (BSD)" );
     219        return 1;
     220    }
     221
     222    len = parseroutes( buf, len, addr );
     223    free( buf );
     224
     225    return len;
     226}
     227
     228#ifndef SA_SIZE
     229#define ROUNDUP( a, size ) \
     230    ( ( (a) & ( (size) - 1 ) ) ? ( 1 + ( (a) | ( (size) - 1 ) ) ) : (a) )
     231#define SA_SIZE( sap ) \
     232    ( sap->sa_len ? ROUNDUP( (sap)->sa_len, sizeof( u_long ) ) : \
     233                    sizeof( u_long ) )
     234#endif /* !SA_SIZE */
     235#define NEXT_SA( sap ) \
     236    (struct sockaddr *) ( (caddr_t) (sap) + ( SA_SIZE( (sap) ) ) )
     237
     238static uint8_t *
     239getroute( int * buflen )
     240{
     241    int     mib[6];
     242    size_t  len;
     243    uint8_t * buf;
     244
     245    mib[0] = CTL_NET;
     246    mib[1] = PF_ROUTE;
     247    mib[2] = 0;
     248    mib[3] = AF_INET;
     249    mib[4] = NET_RT_FLAGS;
     250    mib[5] = RTF_GATEWAY;
     251
     252    if( sysctl( mib, 6, NULL, &len, NULL, 0 ) )
     253    {
     254        if( ENOENT != errno )
     255        {
     256            tr_err( "sysctl net.route.0.inet.flags.gateway failed (%s)",
     257                    strerror( errno ) );
     258        }
     259        *buflen = 0;
     260        return NULL;
     261    }
     262
     263    buf = malloc( len );
     264    if( NULL == buf )
     265    {
     266        *buflen = 0;
     267        return NULL;
     268    }
     269
     270    if( sysctl( mib, 6, buf, &len, NULL, 0 ) )
     271    {
     272        tr_err( "sysctl net.route.0.inet.flags.gateway failed (%s)",
     273                strerror( errno ) );
     274        free( buf );
     275        *buflen = 0;
     276        return NULL;
     277    }
     278
     279    *buflen = len;
     280
     281    return buf;
     282}
     283
     284static int
     285parseroutes( uint8_t * buf, int len, struct in_addr * addr )
     286{
     287    uint8_t            * end;
     288    struct rt_msghdr   * rtm;
     289    struct sockaddr    * sa;
     290    struct sockaddr_in * sin;
     291    int                  ii;
     292    struct in_addr       dest, gw;
     293
     294    end = buf + len;
     295    while( end > buf + sizeof( *rtm ) )
     296    {
     297        rtm = (struct rt_msghdr *) buf;
     298        buf += rtm->rtm_msglen;
     299        if( end >= buf )
     300        {
     301            dest.s_addr = INADDR_NONE;
     302            gw.s_addr   = INADDR_NONE;
     303            sa = (struct sockaddr *) ( rtm + 1 );
     304
     305            for( ii = 0; ii < RTAX_MAX && (uint8_t *) sa < buf; ii++ )
     306            {
     307                if( buf < (uint8_t *) NEXT_SA( sa ) )
     308                {
     309                    break;
     310                }
     311
     312                if( rtm->rtm_addrs & ( 1 << ii ) )
     313                {
     314                    if( AF_INET == sa->sa_family )
     315                    {
     316                        sin = (struct sockaddr_in *) sa;
     317                        switch( ii )
     318                        {
     319                            case RTAX_DST:
     320                                dest = sin->sin_addr;
     321                                break;
     322                            case RTAX_GATEWAY:
     323                                gw = sin->sin_addr;
     324                                break;
     325                        }
     326                    }
     327                    sa = NEXT_SA( sa );
     328                }
     329            }
     330
     331            if( INADDR_ANY == dest.s_addr && INADDR_NONE != gw.s_addr )
     332            {
     333                *addr = gw;
     334                return 0;
     335            }
     336        }
     337    }
     338
     339    return 1;
     340}
     341
     342#elif defined( linux ) || defined( __linux ) || defined( __linux__ )
     343
     344#include <linux/types.h>
     345#include <linux/netlink.h>
     346#include <linux/rtnetlink.h>
     347
     348#define SEQNUM 195909
     349
     350static int
     351getsock( void );
     352static uint8_t *
     353getroute( int fd, unsigned int * buflen );
     354static int
     355parseroutes( uint8_t * buf, unsigned int len, struct in_addr * addr );
     356
     357int
     358tr_getDefaultRoute( struct in_addr * addr )
     359{
     360    int fd, ret;
     361    unsigned int len;
     362    uint8_t * buf;
     363
     364    ret = 1;
     365    fd = getsock();
     366    if( 0 <= fd )
     367    {
     368        while( ret )
     369        {
     370            buf = getroute( fd, &len );
     371            if( NULL == buf )
     372            {
     373                break;
     374            }
     375            ret = parseroutes( buf, len, addr );
     376            free( buf );
     377        }
     378        close( fd );
     379    }
     380
     381    if( ret )
     382    {
     383        tr_err( "failed to get default route (Linux)" );
     384    }
     385
     386    return ret;
     387}
     388
     389static int
     390getsock( void )
     391{
     392    int fd, flags;
     393    struct
     394    {
     395        struct nlmsghdr nlh;
     396        struct rtgenmsg rtg;
     397    } req;
     398    struct sockaddr_nl snl;
     399
     400    fd = socket( PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE );
     401    if( 0 > fd )
     402    {
     403        tr_err( "failed to create routing socket (%s)", strerror( errno ) );
     404        return -1;
     405    }
     406
     407    flags = fcntl( fd, F_GETFL );
     408    if( 0 > flags || 0 > fcntl( fd, F_SETFL, O_NONBLOCK | flags ) )
     409    {
     410        tr_err( "failed to set socket nonblocking (%s)", strerror( errno ) );
     411        close( fd );
     412        return -1;
     413    }
     414
     415    bzero( &snl, sizeof( snl ) );
     416    snl.nl_family = AF_NETLINK;
     417
     418    bzero( &req, sizeof( req ) );
     419    req.nlh.nlmsg_len = NLMSG_LENGTH( sizeof( req.rtg ) );
     420    req.nlh.nlmsg_type = RTM_GETROUTE;
     421    req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
     422    req.nlh.nlmsg_seq = SEQNUM;
     423    req.nlh.nlmsg_pid = 0;
     424    req.rtg.rtgen_family = AF_INET;
     425
     426    if( 0 > sendto( fd, &req, sizeof( req ), 0,
     427                    (struct sockaddr *) &snl, sizeof( snl ) ) )
     428    {
     429        tr_err( "failed to write to routing socket (%s)", strerror( errno ) );
     430        close( fd );
     431        return -1;
     432    }
     433
     434    return fd;
     435}
     436
     437static uint8_t *
     438getroute( int fd, unsigned int * buflen )
     439{
     440    void             * buf;
     441    unsigned int       len;
     442    ssize_t            res;
     443    struct sockaddr_nl snl;
     444    socklen_t          slen;
     445
     446    len = 8192;
     447    buf = calloc( 1, len );
     448    if( NULL == buf )
     449    {
     450        *buflen = 0;
     451        return NULL;
     452    }
     453
     454    for( ;; )
     455    {
     456        bzero( &snl, sizeof( snl ) );
     457        slen = sizeof( snl );
     458        res = recvfrom( fd, buf, len, 0, (struct sockaddr *) &snl, &slen );
     459        if( 0 > res )
     460        {
     461            if( EAGAIN != errno )
     462            {
     463                tr_err( "failed to read from routing socket (%s)",
     464                        strerror( errno ) );
     465            }
     466            free( buf );
     467            *buflen = 0;
     468            return NULL;
     469        }
     470        if( slen < sizeof( snl ) || AF_NETLINK != snl.nl_family )
     471        {
     472            tr_err( "bad address" );
     473            free( buf );
     474            *buflen = 0;
     475            return NULL;
     476        }
     477
     478        if( 0 == snl.nl_pid )
     479        {
     480            break;
     481        }
     482    }
     483
     484    *buflen = res;
     485
     486    return buf;
     487}
     488
     489static int
     490parseroutes( uint8_t * buf, unsigned int len, struct in_addr * addr )
     491{
     492    struct nlmsghdr * nlm;
     493    struct nlmsgerr * nle;
     494    struct rtmsg    * rtm;
     495    struct rtattr   * rta;
     496    int               rtalen;
     497    struct in_addr    gw, dst;
     498
     499    nlm = ( struct nlmsghdr * ) buf;
     500    while( NLMSG_OK( nlm, len ) )
     501    {
     502        gw.s_addr = INADDR_ANY;
     503        dst.s_addr = INADDR_ANY;
     504        if( NLMSG_ERROR == nlm->nlmsg_type )
     505        {
     506            nle = (struct nlmsgerr *) NLMSG_DATA( nlm );
     507            if( NLMSG_LENGTH( NLMSG_ALIGN( sizeof( struct nlmsgerr ) ) ) >
     508                nlm->nlmsg_len )
     509            {
     510                tr_err( "truncated netlink error" );
     511            }
     512            else
     513            {
     514                tr_err( "netlink error (%s)", strerror( nle->error ) );
     515            }
     516            return 1;
     517        }
     518        else if( RTM_NEWROUTE == nlm->nlmsg_type && SEQNUM == nlm->nlmsg_seq &&
     519                 getpid() == (pid_t) nlm->nlmsg_pid &&
     520                 NLMSG_LENGTH( sizeof( struct rtmsg ) ) <= nlm->nlmsg_len )
     521        {
     522            rtm = NLMSG_DATA( nlm );
     523            rta = RTM_RTA( rtm );
     524            rtalen = RTM_PAYLOAD( nlm );
     525
     526            while( RTA_OK( rta, rtalen ) )
     527            {
     528                if( sizeof( struct in_addr ) <= RTA_PAYLOAD( rta ) )
     529                {
     530                    switch( rta->rta_type )
     531                    {
     532                        case RTA_GATEWAY:
     533                            memcpy( &gw, RTA_DATA( rta ), sizeof( gw ) );
     534                            break;
     535                        case RTA_DST:
     536                            memcpy( &dst, RTA_DATA( rta ), sizeof( dst ) );
     537                            break;
     538                    }
     539                }
     540                rta = RTA_NEXT( rta, rtalen );
     541            }
     542        }
     543
     544        if( INADDR_NONE != gw.s_addr && INADDR_ANY != gw.s_addr &&
     545            INADDR_ANY == dst.s_addr )
     546        {
     547            *addr = gw;
     548            return 0;
     549        }
     550
     551        nlm = NLMSG_NEXT( nlm, len );
     552    }
     553
     554    return 1;
     555}
     556
     557#else /* not BSD or Linux */
     558
     559int
     560tr_getDefaultRoute( struct in_addr * addr UNUSED )
     561{
     562    tr_inf( "don't know how to get default route on this platform" );
     563    return 1;
     564}
     565
     566#endif
  • branches/nat-traversal/libtransmission/platform.h

    r310 r864  
    6161}
    6262
     63int
     64tr_getDefaultRoute( struct in_addr * addr );
     65
    6366#endif
  • branches/nat-traversal/libtransmission/tracker.c

    r854 r864  
    4343    uint64_t       dateOk;
    4444
    45 #define TC_STATUS_IDLE    1
    46 #define TC_STATUS_RESOLVE 2
    47 #define TC_STATUS_CONNECT 4
    48 #define TC_STATUS_RECV    8
    49     char           status;
    50 
    5145#define TC_ATTEMPT_NOREACH 1
    5246#define TC_ATTEMPT_ERROR   2
     
    5448    char           lastAttempt;
    5549
    56     tr_resolve_t * resolve;
    57     int            socket;
    58     uint8_t      * buf;
    59     int            size;
    60     int            pos;
     50    tr_http_t    * http;
    6151
    6252    int            bindPort;
     
    6757};
    6858
    69 static void sendQuery  ( tr_tracker_t * tc );
    70 static void recvAnswer ( tr_tracker_t * tc );
     59static tr_http_t * getQuery   ( tr_tracker_t * tc );
     60static void        readAnswer ( tr_tracker_t * tc, const char *, int );
    7161
    7262tr_tracker_t * tr_trackerInit( tr_torrent_t * tor )
     
    8474    tc->leechers = -1;
    8575
    86     tc->status   = TC_STATUS_IDLE;
    8776    tc->lastAttempt = TC_ATTEMPT_NOREACH;
    88     tc->size     = 1024;
    89     tc->buf      = malloc( tc->size );
    9077
    9178    tc->bindPort = *(tor->bindPort);
     
    160147    tr_torrent_t * tor = tc->tor;
    161148    tr_info_t    * inf = &tor->info;
    162     uint64_t       now = tr_date();
    163 
    164     if( ( tc->status & TC_STATUS_IDLE ) && shouldConnect( tc ) )
    165     {
    166         tc->resolve = tr_netResolveInit( inf->trackerAddress );
     149    const char   * data;
     150    int            len;
     151
     152    if( ( NULL == tc->http ) && shouldConnect( tc ) )
     153    {
     154        if( tr_fdSocketWillCreate( tor->fdlimit, 1 ) )
     155        {
     156            return 0;
     157        }
     158        tc->http = getQuery( tc );
    167159
    168160        tr_inf( "Tracker: connecting to %s:%d (%s)",
     
    173165                    ( 0 < tc->newPort ? "sending 'stopped' to change port" :
    174166                      "getting peers" ) ) ) );
    175 
    176         tc->status  = TC_STATUS_RESOLVE;
    177         tc->dateTry = tr_date();
    178     }
    179 
    180     if( tc->status & TC_STATUS_RESOLVE )
    181     {
    182         int ret;
    183         struct in_addr addr;
    184 
    185         ret = tr_netResolvePulse( tc->resolve, &addr );
    186         if( ret == TR_RESOLVE_WAIT )
    187         {
    188             return 0;
    189         }
    190         else
    191         {
    192             tr_netResolveClose( tc->resolve );
    193         }
    194        
    195         if( ret == TR_RESOLVE_ERROR )
    196         {
    197             tc->status = TC_STATUS_IDLE;
    198             return 0;
    199         }
    200 
    201         if( tr_fdSocketWillCreate( tor->fdlimit, 1 ) )
    202         {
    203             tc->status = TC_STATUS_IDLE;
    204             return 0;
    205         }
    206 
    207         tc->socket = tr_netOpen( addr, htons( inf->trackerPort ) );
    208         if( tc->socket < 0 )
    209         {
    210             tr_fdSocketClosed( tor->fdlimit, 1 );
    211             tc->status = TC_STATUS_IDLE;
    212             return 0;
    213         }
    214 
    215         tc->status = TC_STATUS_CONNECT;
    216     }
    217 
    218     if( tc->status & TC_STATUS_CONNECT )
    219     {
    220         /* We are connecting to the tracker. Try to send the query */
    221         sendQuery( tc );
    222     }
    223 
    224     if( tc->status & TC_STATUS_RECV )
    225     {
    226         /* Try to get something */
    227         recvAnswer( tc );
    228     }
    229 
    230     if( tc->status > TC_STATUS_IDLE && now > tc->dateTry + 60000 )
    231     {
    232         /* Give up if the request wasn't successful within 60 seconds */
    233         tr_inf( "Tracker: timeout reached (60 s)" );
    234 
    235         tr_netClose( tc->socket );
    236         tr_fdSocketClosed( tor->fdlimit, 1 );
    237 
    238         tc->status  = TC_STATUS_IDLE;
    239         tc->dateTry = tr_date();
     167    }
     168
     169    if( NULL != tc->http )
     170    {
     171        switch( tr_httpPulse( tc->http, &data, &len ) )
     172        {
     173            case TR_WAIT:
     174                return 0;
     175
     176            case TR_ERROR:
     177                tr_httpClose( tc->http );
     178                tr_fdSocketClosed( tor->fdlimit, 1 );
     179                tc->http = NULL;
     180                return 0;
     181
     182            case TR_OK:
     183                readAnswer( tc, data, len );
     184                tr_httpClose( tc->http );
     185                tc->http = NULL;
     186                tr_fdSocketClosed( tor->fdlimit, 1 );
     187                break;
     188        }
    240189    }
    241190
     
    254203    tr_torrent_t * tor = tc->tor;
    255204
    256     if( tc->status > TC_STATUS_CONNECT )
     205    if( NULL != tc->http )
    257206    {
    258207        /* If we are already sendy a query at the moment, we need to
    259208           reconnect */
    260         tr_netClose( tc->socket );
     209        tr_httpClose( tc->http );
     210        tc->http = NULL;
    261211        tr_fdSocketClosed( tor->fdlimit, 1 );
    262         tc->status = TC_STATUS_IDLE;
    263212    }
    264213
     
    268217
    269218    /* Even if we have connected recently, reconnect right now */
    270     if( tc->status & TC_STATUS_IDLE )
    271     {
    272         tc->dateTry = 0;
    273     }
     219    tc->dateTry = 0;
    274220}
    275221
     
    278224    tr_torrent_t * tor = tc->tor;
    279225
    280     if( tc->status == TC_STATUS_RESOLVE )
    281     {
    282         tr_netResolveClose( tc->resolve );
    283     }
    284     else if( tc->status > TC_STATUS_RESOLVE )
    285     {
    286         tr_netClose( tc->socket );
     226    if( NULL != tc->http )
     227    {
     228        tr_httpClose( tc->http );
    287229        tr_fdSocketClosed( tor->fdlimit, 1 );
    288230    }
    289     free( tc->buf );
    290231    free( tc );
    291232}
    292233
    293 static void sendQuery( tr_tracker_t * tc )
     234static tr_http_t * getQuery( tr_tracker_t * tc )
    294235{
    295236    tr_torrent_t * tor = tc->tor;
    296237    tr_info_t    * inf = &tor->info;
    297238
    298     char     * event;
    299     uint64_t   left;
    300     int        ret;
    301     uint64_t   down;
    302     uint64_t   up;
     239    char         * event;
     240    uint64_t       left;
     241    uint64_t       down;
     242    uint64_t       up;
    303243
    304244    assert( tor->downloaded >= tc->download && tor->uploaded >= tc->upload );
     
    331271    left = tr_cpLeftBytes( tor->completion );
    332272
    333     ret = snprintf( (char *) tc->buf, tc->size,
    334             "GET %s?"
    335             "info_hash=%s&"
    336             "peer_id=%s&"
    337             "port=%d&"
    338             "uploaded=%"PRIu64"&"
    339             "downloaded=%"PRIu64"&"
    340             "left=%"PRIu64"&"
    341             "compact=1&"
    342             "numwant=50&"
    343             "key=%s"
    344             "%s "
    345             "HTTP/1.1\r\n"
    346             "Host: %s\r\n"
    347             "User-Agent: Transmission/%d.%d\r\n"
    348             "Connection: close\r\n\r\n",
    349             inf->trackerAnnounce, tor->hashString, tc->id,
    350             tc->bindPort, up, down,
    351             left, tor->key, event, inf->trackerAddress,
    352             VERSION_MAJOR, VERSION_MINOR );
    353 
    354     ret = tr_netSend( tc->socket, tc->buf, ret );
    355     if( ret & TR_NET_CLOSE )
    356     {
    357         tr_inf( "Tracker: connection failed" );
    358         tr_netClose( tc->socket );
    359         tr_fdSocketClosed( tor->fdlimit, 1 );
    360         tc->status  = TC_STATUS_IDLE;
    361         tc->dateTry = tr_date();
    362     }
    363     else if( !( ret & TR_NET_BLOCK ) )
    364     {
    365         // printf( "Tracker: sent %s", tc->buf );
    366         tc->status = TC_STATUS_RECV;
    367         tc->pos    = 0;
    368     }
    369 }
    370 
    371 static void recvAnswer( tr_tracker_t * tc )
     273    return tr_httpClient( TR_HTTP_GET, inf->trackerAddress,
     274                          inf->trackerPort,
     275                          "%s?"
     276                          "info_hash=%s&"
     277                          "peer_id=%s&"
     278                          "port=%d&"
     279                          "uploaded=%"PRIu64"&"
     280                          "downloaded=%"PRIu64"&"
     281                          "left=%"PRIu64"&"
     282                          "compact=1&"
     283                          "numwant=50&"
     284                          "key=%s"
     285                          "%s ",
     286                          inf->trackerAnnounce, tor->hashString, tc->id,
     287                          tc->bindPort, up, down, left, tor->key, event );
     288}
     289
     290static void readAnswer( tr_tracker_t * tc, const char * data, int len )
    372291{
    373292    tr_torrent_t * tor = tc->tor;
    374     int ret;
    375293    int i;
     294    int code;
    376295    benc_val_t   beAll;
    377296    benc_val_t * bePeers, * beFoo;
    378     uint8_t * body;
     297    const uint8_t * body;
    379298    int bodylen;
    380299    int shouldfree;
    381300
    382     if( tc->pos == tc->size )
    383     {
    384         tc->size *= 2;
    385         tc->buf   = realloc( tc->buf, tc->size );
    386     }
    387    
    388     ret = tr_netRecv( tc->socket, &tc->buf[tc->pos],
    389                     tc->size - tc->pos );
    390 
    391     if( ret & TR_NET_BLOCK )
    392     {
    393         return;
    394     }
    395     if( !( ret & TR_NET_CLOSE ) )
    396     {
    397         // printf( "got %d bytes\n", ret );
    398         tc->pos += ret;
    399         return;
    400     }
    401 
    402     tr_netClose( tc->socket );
    403     tr_fdSocketClosed( tor->fdlimit, 1 );
    404     // printf( "connection closed, got total %d bytes\n", tc->pos );
    405 
    406     tc->status  = TC_STATUS_IDLE;
    407301    tc->dateTry = tr_date();
    408 
    409     if( tc->pos < 12 || ( 0 != memcmp( tc->buf, "HTTP/1.0 ", 9 ) &&
    410                           0 != memcmp( tc->buf, "HTTP/1.1 ", 9 ) ) )
    411     {
    412         /* We don't have a complete HTTP status line */
    413         tr_inf( "Tracker: incomplete HTTP status line" );
     302    code = tr_httpResponseCode( data, len );
     303    if( 0 > code )
     304    {
     305        /* We don't have a valid HTTP status line */
     306        tr_inf( "Tracker: invalid HTTP status line" );
    414307        tc->lastAttempt = TC_ATTEMPT_NOREACH;
    415308        return;
    416309    }
    417310
    418     if( '2' != tc->buf[9] )
     311    if( !TR_HTTP_STATUS_OK( code ) )
    419312    {
    420313        /* we didn't get a 2xx status code */
    421         tr_err( "Tracker: invalid HTTP status code: %c%c%c",
    422                 tc->buf[9], tc->buf[10], tc->buf[11] );
     314        tr_err( "Tracker: invalid HTTP status code: %i", code );
    423315        tc->lastAttempt = TC_ATTEMPT_ERROR;
    424316        return;
     
    426318
    427319    /* find the end of the http headers */
    428     body = tr_memmem( tc->buf, tc->pos, "\015\012\015\012", 4 );
    429     if( NULL != body )
    430     {
    431         body += 4;
    432     }
    433     /* hooray for trackers that violate the HTTP spec */
    434     else if( NULL != ( body = tr_memmem( tc->buf, tc->pos, "\015\015", 2 ) ) ||
    435              NULL != ( body = tr_memmem( tc->buf, tc->pos, "\012\012", 2 ) ) )
    436     {
    437         body += 2;
    438     }
    439     else
     320    body = (uint8_t *) tr_httpParse( data, len, NULL );
     321    if( NULL == body )
    440322    {
    441323        tr_err( "Tracker: could not find end of HTTP headers" );
     
    443325        return;
    444326    }
    445     bodylen = tc->pos - (body - tc->buf);
     327    bodylen = len - (body - (const uint8_t*)data);
    446328
    447329    /* Find and load the dictionary */
     
    611493    tr_info_t * inf = &tor->info;
    612494
    613     int s, i, ret;
    614     uint8_t buf[1024];
    615     benc_val_t scrape, * val1, * val2;
    616     struct in_addr addr;
    617     uint64_t date;
    618     int pos, len;
    619     tr_resolve_t * resolve;
     495    tr_http_t  * http;
     496    const char * data, * body;
     497    int          datalen, bodylen;
     498    int          code, ii;
     499    benc_val_t   scrape, * val1, * val2;
    620500
    621501    if( !tor->scrape[0] )
     
    625505    }
    626506
    627     resolve = tr_netResolveInit( inf->trackerAddress );
    628     for( date = tr_date();; )
    629     {
    630         ret = tr_netResolvePulse( resolve, &addr );
    631         if( ret == TR_RESOLVE_OK )
    632         {
    633             tr_netResolveClose( resolve );
     507    http = tr_httpClient( TR_HTTP_GET, inf->trackerAddress, inf->trackerPort,
     508                          "%s?info_hash=%s", tor->scrape, tor->hashString );
     509
     510    data = NULL;
     511    while( NULL == data )
     512    {
     513        switch( tr_httpPulse( http, &data, &datalen ) )
     514        {
     515            case TR_WAIT:
     516                break;
     517
     518            case TR_ERROR:
     519                tr_httpClose( http );
     520                return 1;
     521
     522            case TR_OK:
     523                if( NULL == data || 0 >= datalen )
     524                {
     525                    tr_httpClose( http );
     526                    return 1;
     527                }
     528                break;
     529        }
     530        tr_wait( 10 );
     531    }
     532
     533    code = tr_httpResponseCode( data, datalen );
     534    if( !TR_HTTP_STATUS_OK( code ) )
     535    {
     536        tr_httpClose( http );
     537        return 1;
     538    }
     539
     540    body = tr_httpParse( data, datalen , NULL );
     541    if( NULL == body )
     542    {
     543        tr_httpClose( http );
     544        return 1;
     545    }
     546    bodylen = datalen - ( body - data );
     547
     548    for( ii = 0; ii < bodylen - 8; ii++ )
     549    {
     550        if( !memcmp( body + ii, "d5:files", 8 ) )
     551        {
    634552            break;
    635553        }
    636         if( ret == TR_RESOLVE_ERROR ||
    637             ( ret == TR_RESOLVE_WAIT && tr_date() > date + 10000 ) )
    638         {
    639             tr_err( "Could not resolve %s", inf->trackerAddress );
    640             tr_netResolveClose( resolve );
    641             return 1;
    642         }
    643         tr_wait( 10 );
    644     }
    645 
    646     s = tr_netOpen( addr, htons( inf->trackerPort ) );
    647     if( s < 0 )
    648     {
    649         return 1;
    650     }
    651 
    652     len = snprintf( (char *) buf, sizeof( buf ),
    653               "GET %s?info_hash=%s HTTP/1.1\r\n"
    654               "Host: %s\r\n"
    655               "Connection: close\r\n\r\n",
    656               tor->scrape, tor->hashString,
    657               inf->trackerAddress );
    658 
    659     for( date = tr_date();; )
    660     {
    661         ret = tr_netSend( s, buf, len );
    662         if( ret & TR_NET_CLOSE )
    663         {
    664             tr_err( "Could not connect to tracker" );
    665             tr_netClose( s );
    666             return 1;
    667         }
    668         else if( ret & TR_NET_BLOCK )
    669         {
    670             if( tr_date() > date + 10000 )
    671             {
    672                 tr_err( "Could not connect to tracker" );
    673                 tr_netClose( s );
    674                 return 1;
    675             }
    676         }
    677         else
    678         {
    679             break;
    680         }
    681         tr_wait( 10 );
    682     }
    683 
    684     pos = 0;
    685     for( date = tr_date();; )
    686     {
    687         ret = tr_netRecv( s, &buf[pos], sizeof( buf ) - pos );
    688         if( ret & TR_NET_CLOSE )
    689         {
    690             break;
    691         }
    692         else if( ret & TR_NET_BLOCK )
    693         {
    694             if( tr_date() > date + 10000 )
    695             {
    696                 tr_err( "Could not read from tracker" );
    697                 tr_netClose( s );
    698                 return 1;
    699             }
    700         }
    701         else
    702         {
    703             pos += ret;
    704         }
    705         tr_wait( 10 );
    706     }
    707 
    708     if( pos < 1 )
    709     {
    710         tr_err( "Could not read from tracker" );
    711         tr_netClose( s );
    712         return 1;
    713     }
    714 
    715     for( i = 0; i < pos - 8; i++ )
    716     {
    717         if( !memcmp( &buf[i], "d5:files", 8 ) )
    718         {
    719             break;
    720         }
    721     }
    722     if( i >= pos - 8 )
    723     {
    724         return 1;
    725     }
    726     if( tr_bencLoad( &buf[i], pos - i, &scrape, NULL ) )
    727     {
     554    }
     555    if( ii >= bodylen - 8 )
     556    {
     557        tr_httpClose( http );
     558        return 1;
     559    }
     560    if( tr_bencLoad( body + ii, bodylen - ii, &scrape, NULL ) )
     561    {
     562        tr_httpClose( http );
    728563        return 1;
    729564    }
     
    732567    if( !val1 )
    733568    {
     569        tr_bencFree( &scrape );
     570        tr_httpClose( http );
    734571        return 1;
    735572    }
     
    737574    if( !val1 )
    738575    {
     576        tr_bencFree( &scrape );
     577        tr_httpClose( http );
    739578        return 1;
    740579    }
     
    742581    if( !val2 )
    743582    {
     583        tr_bencFree( &scrape );
     584        tr_httpClose( http );
    744585        return 1;
    745586    }
     
    748589    if( !val2 )
    749590    {
     591        tr_bencFree( &scrape );
     592        tr_httpClose( http );
    750593        return 1;
    751594    }
    752595    *leechers = val2->val.i;
    753596    tr_bencFree( &scrape );
     597    tr_httpClose( http );
    754598
    755599    return 0;
  • branches/nat-traversal/libtransmission/transmission.c

    r815 r864  
    7575    h->fdlimit  = tr_fdInit();
    7676    h->choking  = tr_chokingInit( h );
     77    h->natpmp   = tr_natpmpInit( h->fdlimit );
     78    h->upnp     = tr_upnpInit( h->fdlimit );
    7779
    7880    h->bindPort = -1;
     
    105107    {
    106108        /* XXX should handle failure here in a better way */
    107         sock = tr_netBind( port );
     109        sock = tr_netBindTCP( port );
     110        if( 0 > sock)
     111        {
     112            tr_fdSocketClosed( h->fdlimit, 0 );
     113        }
     114        else
     115        {   
     116            tr_inf( "Bound listening port %d", port );
     117            listen( sock, 5 );
     118        }
    108119    }
    109120#else
     
    133144    h->bindSocket = sock;
    134145
     146    tr_natpmpForwardPort( h->natpmp, port );
     147    tr_upnpForwardPort( h->upnp, port );
     148
    135149    tr_lockUnlock( &h->acceptLock );
     150}
     151
     152void tr_natTraversalEnable( tr_handle_t * h )
     153{
     154    tr_natpmpStart( h->natpmp );
     155    tr_upnpStart( h->upnp );
     156}
     157
     158void tr_natTraversalDisable( tr_handle_t * h )
     159{
     160    tr_natpmpStop( h->natpmp );
     161    tr_upnpStop( h->upnp );
     162}
     163
     164int tr_natTraversalStatus( tr_handle_t * h )
     165{
     166    int statuses[] = {
     167        TR_NAT_TRAVERSAL_MAPPED,
     168        TR_NAT_TRAVERSAL_MAPPING,
     169        TR_NAT_TRAVERSAL_UNMAPPING,
     170        TR_NAT_TRAVERSAL_ERROR,
     171        TR_NAT_TRAVERSAL_NOTFOUND,
     172        TR_NAT_TRAVERSAL_DISABLED,
     173        -1,
     174    };
     175    int natpmp, upnp, ii;
     176
     177    natpmp = tr_natpmpStatus( h->natpmp );
     178    upnp = tr_upnpStatus( h->upnp );
     179
     180    for( ii = 0; 0 <= statuses[ii]; ii++ )
     181    {
     182        if( statuses[ii] == natpmp || statuses[ii] == upnp )
     183        {
     184            return statuses[ii];
     185        }
     186    }
     187
     188    assert( 0 );
     189
     190    return TR_NAT_TRAVERSAL_ERROR;
    136191}
    137192
     
    630685{
    631686    acceptStop( h );
     687    tr_natpmpClose( h->natpmp );
     688    tr_upnpClose( h->upnp );
    632689    tr_chokingClose( h->choking );
    633690    tr_fdClose( h->fdlimit );
     
    735792    {
    736793        date1 = tr_date();
     794
     795        /* do NAT-PMP and UPnP pulses here since there's nowhere better */
     796        tr_natpmpPulse( h->natpmp );
     797        tr_upnpPulse( h->upnp );
    737798
    738799        /* Check for incoming connections */
  • branches/nat-traversal/libtransmission/transmission.h

    r817 r864  
    100100 * tr_setBindPort
    101101 ***********************************************************************
    102  * Sets the port to listen for incoming peer connections
     102 * Sets the port to listen for incoming peer connections.
     103 * This can be safely called even with active torrents.
    103104 **********************************************************************/
    104105void tr_setBindPort( tr_handle_t *, int );
     106
     107/***********************************************************************
     108 * tr_natTraversalEnable
     109 * tr_natTraversalDisable
     110 ***********************************************************************
     111 * Enable or disable NAT traversal using NAT-PMP or UPnP IGD.
     112 **********************************************************************/
     113void tr_natTraversalEnable( tr_handle_t * );
     114void tr_natTraversalDisable( tr_handle_t * );
     115
     116/***********************************************************************
     117 * tr_natTraversalStatus
     118 ***********************************************************************
     119 * Return the status of NAT traversal
     120 **********************************************************************/
     121#define TR_NAT_TRAVERSAL_MAPPING        1
     122#define TR_NAT_TRAVERSAL_MAPPED         2
     123#define TR_NAT_TRAVERSAL_NOTFOUND       3
     124#define TR_NAT_TRAVERSAL_ERROR          4
     125#define TR_NAT_TRAVERSAL_UNMAPPING      5
     126#define TR_NAT_TRAVERSAL_DISABLED       6
     127#define TR_NAT_TRAVERSAL_IS_DISABLED( st ) \
     128  ( TR_NAT_TRAVERSAL_DISABLED == (st) || TR_NAT_TRAVERSAL_UNMAPPING == (st) )
     129int tr_natTraversalStatus( tr_handle_t * );
    105130
    106131/***********************************************************************
  • branches/nat-traversal/libtransmission/utils.c

    r837 r864  
    2525#include "transmission.h"
    2626
     27#define SPRINTF_BUFSIZE         100
     28
    2729static tr_lock_t      * messageLock = NULL;
    2830static int              messageLevel = 0;
     
    9799void tr_msg( int level, char * msg, ... )
    98100{
    99     va_list          args;
     101    va_list         args1, args2;
    100102    tr_msg_list_t * newmsg;
     103    int             len1, len2;
    101104
    102105    assert( NULL != messageLock );
     
    113116    if( messageLevel >= level )
    114117    {
    115         va_start( args, msg );
     118        va_start( args1, msg );
    116119        if( messageQueuing )
    117120        {
     
    121124                newmsg->level = level;
    122125                newmsg->when = time( NULL );
    123                 vasprintf( &newmsg->message, msg, args );
     126                len1 = len2 = 0;
     127                va_start( args2, msg );
     128                tr_vsprintf( &newmsg->message, &len1, &len2, msg,
     129                             args1, args2 );
     130                va_end( args2 );
    124131                if( NULL == newmsg->message )
    125132                {
     
    135142        else
    136143        {
    137             vfprintf( stderr, msg, args );
     144            vfprintf( stderr, msg, args1 );
    138145            fputc( '\n', stderr );
    139146        }
    140         va_end( args );
     147        va_end( args1 );
    141148    }
    142149
     
    235242    return 0;
    236243}
     244
     245#define UPPER( cc ) \
     246    ( 'a' <= (cc) && 'z' >= (cc) ? (cc) - ( 'a' - 'A' ) : (cc) )
     247
     248int tr_strncasecmp( const char * first, const char * second, int len )
     249{
     250    int ii;
     251    char firstchar, secondchar;
     252
     253    if( 0 > len )
     254    {
     255        len = strlen( first );
     256        ii = strlen( second );
     257        len = MIN( len, ii );
     258    }
     259
     260    for( ii = 0; ii < len; ii++ )
     261    {
     262        if( first[ii] != second[ii] )
     263        {
     264            firstchar = UPPER( first[ii] );
     265            secondchar = UPPER( second[ii] );
     266            if( firstchar > secondchar )
     267            {
     268                return 1;
     269            }
     270            else if( firstchar < secondchar )
     271            {
     272                return -1;
     273            }
     274        }
     275        if( '\0' == first[ii] )
     276        {
     277            /* if first[ii] is '\0' then second[ii] is too */
     278            return 0;
     279        }
     280    }
     281
     282    return 0;
     283}
     284
     285int tr_sprintf( char ** buf, int * used, int * max, const char * format, ... )
     286{
     287    va_list ap1, ap2;
     288    int     ret;
     289
     290    va_start( ap1, format );
     291    va_start( ap2, format );
     292    ret = tr_vsprintf( buf, used, max, format, ap1, ap2 );
     293    va_end( ap2 );
     294    va_end( ap1 );
     295
     296    return ret;
     297}
     298
     299int tr_vsprintf( char ** buf, int * used, int * max, const char * fmt,
     300                 va_list ap1, va_list ap2 )
     301{
     302    int     want;
     303    char  * newbuf;
     304
     305    want = vsnprintf( NULL, 0, fmt, ap1 );
     306
     307    while( *used + want + 1 > *max )
     308    {
     309        *max += SPRINTF_BUFSIZE;
     310        newbuf = realloc( *buf, *max );
     311        if( NULL == newbuf )
     312        {
     313            return 1;
     314        }
     315        *buf = newbuf;
     316    }
     317
     318    *used += vsnprintf( *buf + *used, *max - *used, fmt, ap2 );
     319
     320    return 0;
     321}
     322
     323char *
     324tr_dupstr( const char * base, int len )
     325{
     326    char * ret;
     327
     328    ret = malloc( len + 1 );
     329    if( NULL != ret )
     330    {
     331        memcpy( ret, base, len );
     332        ret[len] = '\0';
     333    }
     334
     335    return ret;
     336}
  • branches/nat-traversal/libtransmission/utils.h

    r815 r864  
    3131#define tr_inf( a... ) tr_msg( TR_MSG_INF, ## a )
    3232#define tr_dbg( a... ) tr_msg( TR_MSG_DBG, ## a )
    33 void tr_msg  ( int level, char * msg, ... );
     33void tr_msg  ( int level, char * msg, ... ) PRINTF( 2, 3 );
    3434
    3535int  tr_rand ( int );
     
    4444 **********************************************************************/
    4545int tr_mkdir( char * path );
     46
     47/***********************************************************************
     48 * tr_strcasecmp
     49 ***********************************************************************
     50 * A case-insensitive strncmp()
     51 **********************************************************************/
     52#define tr_strcasecmp( ff, ss ) ( tr_strncasecmp( (ff), (ss), -1 ) )
     53int tr_strncasecmp( const char * first, const char * second, int len );
     54
     55/***********************************************************************
     56 * tr_sprintf
     57 ***********************************************************************
     58 * Appends to the end of a buffer using printf formatting,
     59 * growing the buffer if needed
     60 **********************************************************************/
     61int tr_sprintf( char ** buf, int * used, int * max,
     62                const char * format, ... ) PRINTF( 4, 5 );
     63/* gee, it sure would be nice if BeOS had va_copy() */
     64int tr_vsprintf( char **, int *, int *, const char *, va_list, va_list );
     65
     66/***********************************************************************
     67 * tr_dupstr
     68 ***********************************************************************
     69 * Creates a nul-terminated string
     70 **********************************************************************/
     71char * tr_dupstr( const char * base, int len );
    4672
    4773/***********************************************************************
  • branches/nat-traversal/mk/common.mk

    r517 r864  
    11# $Id$
    22
    3 TMPCFLAGS   = -g -Wall -W -O3 -funroll-loops -D_FILE_OFFSET_BITS=64 \
     3TMPCFLAGS   = -g -Wall -W -D_FILE_OFFSET_BITS=64 \
    44              -D_LARGEFILE_SOURCE -D_GNU_SOURCE \
    55              -DSYS_$(shell echo $(SYSTEM) | tr a-z A-Z)
  • branches/nat-traversal/mk/lib.mk

    r265 r864  
    66SRCS = transmission.c bencode.c net.c tracker.c peer.c inout.c \
    77       metainfo.c sha1.c utils.c fdlimit.c clients.c completion.c \
    8        platform.c ratecontrol.c choking.c
     8       platform.c ratecontrol.c choking.c natpmp.c upnp.c http.c xml.c
    99OBJS = $(SRCS:%.c=%.o)
    1010
Note: See TracChangeset for help on using the changeset viewer.