Ticket #159: source-ip.patch

File source-ip.patch, 15.0 KB (added by pihhan, 15 years ago)

Patch for enabling source binding and port binding.

  • http.c

     
    8181    */
    8282    int            chunkoff;
    8383    int            chunklen;
     84
     85    tr_source_t *  source;
    8486};
    8587
    8688int
     
    377379}
    378380
    379381tr_http_t *
     382tr_httpClientSource( int method, const char * host, int port, tr_source_t *source, const char * fmt, ... )
     383{
     384    tr_http_t    * http;
     385    va_list        ap1, ap2;
     386    char         * methodstr;
     387
     388    http = malloc( sizeof( *http ) );
     389    if( NULL == http )
     390    {
     391        return NULL;
     392    }
     393
     394    memset( http, 0, sizeof( *http ) );
     395    http->state      = HTTP_STATE_CONSTRUCT;
     396    http->lengthtype = HTTP_LENGTH_UNKNOWN;
     397    http->host       = strdup( host );
     398    http->port       = port;
     399    http->sock       = -1;
     400    http->source     = source;
     401
     402    if( NULL == http->host || NULL == fmt )
     403    {
     404        goto err;
     405    }
     406
     407    switch( method )
     408    {
     409        case TR_HTTP_GET:
     410            methodstr = "GET";
     411            break;
     412        case TR_HTTP_POST:
     413            methodstr = "POST";
     414            break;
     415        case TR_HTTP_M_POST:
     416            methodstr = "M-POST";
     417            break;
     418        default:
     419            goto err;
     420    }
     421    if( tr_sprintf( EXPANDBUF( http->header ), "%s ", methodstr ) )
     422    {
     423        goto err;
     424    }
     425
     426    va_start( ap1, fmt );
     427    va_start( ap2, fmt );
     428    if( tr_vsprintf( EXPANDBUF( http->header ), fmt, ap1, ap2 ) )
     429    {
     430        va_end( ap2 );
     431        va_end( ap1 );
     432        goto err;
     433    }
     434    va_end( ap2 );
     435    va_end( ap1 );
     436
     437    if( tr_sprintf( EXPANDBUF( http->header ), " HTTP/1.1" CR LF
     438                    "Host: %s" CR LF
     439                    "User-Agent: Transmission/%d.%d" CR LF
     440                    "Connection: close" CR LF,
     441                    http->host, VERSION_MAJOR, VERSION_MINOR ) )
     442    {
     443        goto err;
     444    }
     445
     446    return http;
     447
     448  err:
     449    tr_httpClose( http );
     450    return NULL;
     451}
     452
     453tr_http_t *
    380454tr_httpClient( int method, const char * host, int port, const char * fmt, ... )
    381455{
    382456    tr_http_t    * http;
     
    501575            }
    502576            if( !tr_netResolve( http->host, &addr ) )
    503577            {
    504                 http->sock = tr_netOpenTCP( addr, htons( http->port ) );
     578                http->sock = tr_netOpenSourceTCP( addr, htons( http->port ), http->source );
    505579                http->state = HTTP_STATE_CONNECT;
    506580                break;
    507581            }
  • peerutils.h

     
    151151    if( ( peer->status & PEER_STATUS_IDLE ) &&
    152152        !tr_fdSocketWillCreate( tor->fdlimit, 0 ) )
    153153    {
    154         peer->socket = tr_netOpenTCP( peer->addr, peer->port );
     154        peer->socket = tr_netOpenSourceTCP( peer->addr, peer->port, tor->source );
    155155        if( peer->socket < 0 )
    156156        {
    157157            peer_dbg( "connection failed" );
  • http.h

     
    5757#define TR_HTTP_M_POST          3
    5858tr_http_t   * tr_httpClient( int, const char *, int, const char *, ... )
    5959              PRINTF( 4, 5 );
     60tr_http_t *
     61tr_httpClientSource( int method, const char * host, int port, tr_source_t *source, const char * fmt, ... )
     62              PRINTF( 5, 6 );
    6063/* only add headers or body before first pulse */
    6164void          tr_httpAddHeader( tr_http_t *, const char *, const char * );
    6265void          tr_httpAddBody( tr_http_t *, const char *, ... ) PRINTF( 2, 3 );
     
    6467char        * tr_httpWhatsMyAddress( tr_http_t * );
    6568void          tr_httpClose( tr_http_t * );
    6669
     70
    6771#endif
  • transmission.c

     
    8484    tr_lockInit( &h->acceptLock );
    8585    tr_threadCreate( &h->acceptThread, acceptLoop, h );
    8686
     87    /* This would not be needed, unless someone enable source settings after torrents started. */
     88    tr_lockInit( &h->source_lock );
     89
    8790    return h;
    8891}
    8992
     
    106109    if( !tr_fdSocketWillCreate( h->fdlimit, 0 ) )
    107110    {
    108111        /* XXX should handle failure here in a better way */
    109         sock = tr_netBindTCP( port );
     112        sock = tr_netBindSourceTCP( port, h->source );
    110113        if( 0 > sock)
    111114        {
    112115            tr_fdSocketClosed( h->fdlimit, 0 );
     
    302305    tor->bindPort = &h->bindPort;
    303306        tor->finished = 0;
    304307
     308    tor->source = h->source;
    305309
    306310    /* Guess scrape URL */
    307311    s1 = strchr( inf->trackerAnnounce, '/' );
  • transmission.h

     
    292292void tr_torrentClose( tr_handle_t *, tr_torrent_t * );
    293293
    294294/***********************************************************************
     295 * tr_setSourceAddr
     296 ***********************************************************************
     297 * Allow you binding outgoing connections to some IP, possibly also
     298 * specify source ports. And at last, you can specify IP ToS header
     299 * to such connections.
     300 **********************************************************************/
     301void tr_setSourceAddr( tr_handle_t *h, char * textaddr );
     302void tr_setSourcePorts( tr_handle_t *h, const unsigned int lowport, const unsigned int highport );
     303void tr_setSourceTOS( tr_handle_t *h, char tos );
     304
     305/***********************************************************************
    295306 * tr_info_s
    296307 **********************************************************************/
    297308typedef struct tr_file_s
     
    388399    struct tr_msg_list_s * next;
    389400};
    390401
     402
    391403#ifdef __TRANSMISSION__
    392404#  include "internal.h"
    393405#endif
  • internal.h

     
    135135#include "http.h"
    136136#include "xml.h"
    137137
     138
    138139struct tr_torrent_s
    139140{
    140141    tr_info_t info;
     
    191192
    192193    tr_torrent_t    * prev;
    193194    tr_torrent_t    * next;
     195
     196    tr_source_t     * source;
    194197};
    195198
    196199#include "utils.h"
     
    220223    volatile char  acceptDie;
    221224    tr_thread_t    acceptThread;
    222225    tr_lock_t      acceptLock;
     226
     227    tr_source_t *  source;
     228    /* FIXME: Is lock really needed? is used whenever needed? */
     229    tr_lock_t      source_lock;
    223230};
    224231
    225232#endif
  • net.c

     
    2424
    2525#include "transmission.h"
    2626
     27#define TR_DEFAULT_LOW_PORT 0
     28#define TR_DEFAULT_HIGH_PORT 65534
     29#ifndef IPTOS_THROUGHPUT
     30#define IPTOS_THROUGHPUT 0x08
     31#endif
     32#define TR_DEFAULT_TOS  IPTOS_THROUGHPUT
     33
    2734/***********************************************************************
    2835 * DNS resolution
    2936 **********************************************************************/
     
    293300    return s;
    294301}
    295302
     303/** Open new connection, but also with source IP and/or port. */
     304int tr_netOpenSource( struct in_addr addr, in_port_t port, int type, tr_source_t *source )
     305{
     306    int s;
     307    struct sockaddr_in sock;
     308
     309    s = createSocket( type );
     310    if( s < 0 )
     311    {
     312        return -1;
     313    }
     314
     315    if (source) {
     316            struct sockaddr_in s_sock;
     317
     318            s_sock.sin_family = AF_INET;
     319            s_sock.sin_addr = source->addr;
     320            if (source->low_port) {
     321                    /* source port is specified, bind to specific port */
     322                    unsigned int p;
     323                    unsigned int nf;
     324                    int success = 0;
     325                   
     326                    tr_lockLock( &source->lock);
     327                    nf = source->next_free_port;
     328                    tr_lockUnlock( &source->lock);
     329
     330                    /* loop over next free ports, try to bind with each one */
     331                    for ( p = nf; p<= source->high_port; p++ ) {
     332                            s_sock.sin_port = htons(p);
     333                            if (!bind(s, &s_sock, sizeof(struct sockaddr_in)) ) {
     334                                    success = 1;
     335                                    nf = p;
     336                                    break;
     337                            }
     338                           
     339                    }
     340
     341                    if (!success) {
     342                            /* we have failed from last known free port to maximum. retry from low to last known-1 */
     343                            for ( p = source->low_port; p<= nf-1; p++ ) {
     344                                    s_sock.sin_port = htons(p);
     345                                    if (!bind(s, &s_sock, sizeof(struct sockaddr_in)) ) {
     346                                            success = 1;
     347                                            nf = p;
     348                                            break;
     349                                    }
     350                            }       
     351                            tr_err( "Failed binding with all ports in range (%s)", strerror( errno ) );
     352                            tr_netClose( s );
     353                            return -1;
     354                    } else {
     355                            if (nf > source->high_port)
     356                                    nf = source->low_port;
     357                            tr_lockLock( &source->lock);
     358                            source->next_free_port = nf;
     359                            tr_lockUnlock( &source->lock);         
     360                    }
     361                    if (source->tos > 0) {
     362                            int opt = source->tos;
     363                            if (setsockopt(s, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)) == -1) {
     364                                    tr_err("Setting priority to %d failed: %s", opt, strerror( errno ));
     365                            }
     366                    }
     367            }
     368            /* finish with source binding hell. now we are going to try connection */
     369    }
     370
     371    memset( &sock, 0, sizeof( sock ) );
     372    sock.sin_family      = AF_INET;
     373    sock.sin_addr.s_addr = addr.s_addr;
     374    sock.sin_port        = port;
     375
     376    if( connect( s, (struct sockaddr *) &sock,
     377                 sizeof( struct sockaddr_in ) ) < 0 &&
     378        errno != EINPROGRESS )
     379    {
     380        tr_err( "Could not connect socket (%s)", strerror( errno ) );
     381        tr_netClose( s );
     382        return -1;
     383    }
     384
     385    return s;
     386}
     387
    296388#ifdef IP_ADD_MEMBERSHIP
    297389int tr_netMcastOpen( int port, struct in_addr addr )
    298390{
     
    367459    return s;
    368460}
    369461
     462int tr_netBindSource( int port, int type, tr_source_t *source )
     463{
     464    int s;
     465    struct sockaddr_in sock;
     466#if defined( SO_REUSEADDR ) || defined( SO_REUSEPORT )
     467    int optval;
     468#endif
     469
     470    s = createSocket( type );
     471    if( s < 0 )
     472    {
     473        return -1;
     474    }
     475
     476#ifdef SO_REUSEADDR
     477    optval = 1;
     478    setsockopt( s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof( optval ) );
     479#endif
     480
     481#ifdef SO_REUSEPORT
     482    if( SOCK_DGRAM == type )
     483    {
     484        optval = 1;
     485        setsockopt( s, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof( optval ) );
     486    }
     487#endif
     488
     489    memset( &sock, 0, sizeof( sock ) );
     490    sock.sin_family      = AF_INET;
     491    if (source) {
     492        sock.sin_addr      = source->addr;
     493    } else {
     494        sock.sin_addr.s_addr = INADDR_ANY;
     495    }
     496    sock.sin_port        = htons( port );
     497
     498    if( bind( s, (struct sockaddr *) &sock,
     499               sizeof( struct sockaddr_in ) ) )
     500    {
     501        tr_err( "Could not bind addr or port %d", port );
     502        tr_netClose( s );
     503        return -1;
     504    }
     505
     506    return s;
     507}
     508
    370509int tr_netAccept( int s, struct in_addr * addr, in_port_t * port )
    371510{
    372511    int t;
     
    450589    snprintf( buf, len, "%hhu.%hhu.%hhu.%hhu",
    451590              cast[0], cast[1], cast[2], cast[3] );
    452591}
     592
     593/* allow binding to source ip and/or port */
     594tr_source_t *tr_sourceInit(tr_handle_t *h)
     595{
     596        tr_source_t *src = NULL;
     597
     598        src = malloc(sizeof(tr_source_t));
     599        if (src) {
     600                src->addr.s_addr = INADDR_ANY;
     601                src->low_port = TR_DEFAULT_LOW_PORT;
     602                src->high_port = TR_DEFAULT_HIGH_PORT;
     603                src->next_free_port = TR_DEFAULT_LOW_PORT;
     604                src->tos = TR_DEFAULT_TOS;
     605                tr_lockInit( &src->lock );
     606                if (h) {
     607                        tr_lockInit( &h->source_lock );
     608                }
     609        }
     610        if (h) {
     611                tr_lockLock( &h->source_lock );
     612                h->source = src;
     613                tr_lockUnlock( &h->source_lock );
     614        }
     615        return src;
     616}
     617
     618/* Set outgoing address of connections */
     619void tr_setSourceAddr( tr_handle_t *h, char * textaddr )
     620{
     621        if (!h->source) {
     622                tr_sourceInit(h);
     623        }
     624        if (!h->source) return;
     625        if (!tr_netResolve(textaddr, &h->source->addr)) {
     626                tr_err("Cannot bind to invalid address %s.", textaddr);
     627        }
     628}
     629
     630/* Allow outgoing connection only from ports lowport to highport */
     631void tr_setSourcePorts( tr_handle_t *h, const unsigned int lowport, const unsigned int highport )
     632{
     633        if (!h->source) {
     634                tr_sourceInit(h);
     635        }
     636        if (!h->source) return;
     637        h->source->low_port = lowport;
     638        if (highport > 0) {
     639                h->source->high_port = highport;
     640        } else  h->source->high_port = 65534; /* if unspecified, allow maximal value */
     641        h->source->next_free_port = lowport;
     642}
     643
     644/* Set Type of Service IP header for each connection */
     645void tr_setSourceTOS( tr_handle_t *h, char tos )
     646{
     647        if (!h->source) {
     648                tr_sourceInit(h);
     649        }
     650        if (!h->source) return;
     651        h->source->tos = tos;
     652}
     653
  • net.h

     
    3939/***********************************************************************
    4040 * TCP sockets
    4141 **********************************************************************/
     42/* changed for source binding */
    4243#define tr_netOpenTCP( addr, port ) tr_netOpen( (addr), (port), SOCK_STREAM )
    4344#define tr_netOpenUDP( addr, port ) tr_netOpen( (addr), (port), SOCK_DGRAM )
     45/*
     46#define tr_netOpenTCP( addr, port ) tr_netOpenSource( (addr), (port), SOCK_STREAM, NULL )
     47#define tr_netOpenUDP( addr, port ) tr_netOpenSource( (addr), (port), SOCK_DGRAM, NULL )
     48*/
     49#define tr_netOpenSourceTCP( addr, port, source ) tr_netOpenSource( (addr), (port), SOCK_STREAM, source )
     50#define tr_netOpenSourceUDP( addr, port, source ) tr_netOpenSource( (addr), (port), SOCK_DGRAM, source )
    4451int  tr_netOpen    ( struct in_addr addr, in_port_t port, int type );
    4552int  tr_netMcastOpen( int port, struct in_addr addr );
    4653#define tr_netBindTCP( port ) tr_netBind( (port), SOCK_STREAM )
    4754#define tr_netBindUDP( port ) tr_netBind( (port), SOCK_DGRAM )
     55#define tr_netBindSourceTCP( port, source ) tr_netBindSource( (port), SOCK_STREAM, source )
     56#define tr_netBindSourceUDP( port, source ) tr_netBindSource( (port), SOCK_DGRAM, source )
    4857int  tr_netBind    ( int port, int type );
    4958int  tr_netAccept  ( int s, struct in_addr *, in_port_t * );
    5059void tr_netClose   ( int s );
     
    5665int  tr_netRecvFrom( int s, uint8_t * buf, int size, struct sockaddr_in * );
    5766
    5867void tr_netNtop( const struct in_addr * addr, char * buf, int len );
     68
     69typedef struct tr_source_s tr_source_t;
     70int tr_netOpenSource( struct in_addr addr, in_port_t port, int type, tr_source_t *source );
     71int tr_netBindSource( int port, int type, tr_source_t *source );
     72
     73
     74struct tr_source_s
     75{
     76        /* allow binding to source address and source ports */
     77        struct in_addr  addr;
     78        unsigned int    low_port;
     79        unsigned int    high_port;
     80        unsigned int    next_free_port;
     81        char            tos;
     82        tr_lock_t       lock;   /* lock for next_free_port locking */
     83};
     84
     85
  • tracker.c

     
    240240
    241241    down = tor->downloadedCur;
    242242    up = tor->uploadedCur;
     243
    243244    if( tc->started )
    244245    {
    245246        event = "&event=started";
     
    275276
    276277    left = tr_cpLeftBytes( tor->completion );
    277278
    278     return tr_httpClient( TR_HTTP_GET, inf->trackerAddress,
    279                           inf->trackerPort,
     279    return tr_httpClientSource( TR_HTTP_GET, inf->trackerAddress,
     280                          inf->trackerPort, tor->source,
    280281                          "%s%s"
    281282                          "info_hash=%s&"
    282283                          "peer_id=%s&"