Ticket #471: nat-rework.diff

File nat-rework.diff, 74.5 KB (added by tiennou, 15 years ago)

Patch v2 : +NAT-PMP

  • libtransmission/natpmp.c

    Property changes on: .
    ___________________________________________________________________
    Name: svn:externals
       - third-party/libevent  http://levent.svn.sourceforge.net/svnroot/levent/branches/patches-1.4/libevent
    
       + third-party/libevent  http://levent.svn.sourceforge.net/svnroot/levent/branches/patches-1.4/libevent
    third-party/pmpmyapp  svn://svn.geekisp.com/bleep/trunk/PmpMyApp/source
    
    
     
    1 /******************************************************************************
    2  * $Id$
    3  *
    4  * Copyright (c) 2006 Transmission authors and contributors
    5  *
    6  * Permission is hereby granted, free of charge, to any person obtaining a
    7  * copy of this software and associated documentation files (the "Software"),
    8  * to deal in the Software without restriction, including without limitation
    9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
    10  * and/or sell copies of the Software, and to permit persons to whom the
    11  * Software is furnished to do so, subject to the following conditions:
    12  *
    13  * The above copyright notice and this permission notice shall be included in
    14  * all copies or substantial portions of the Software.
    15  *
    16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    22  * DEALINGS IN THE SOFTWARE.
    23  *****************************************************************************/
    24 
    25 #include <assert.h>
    26 #include <errno.h>
    27 #include <stdlib.h>
    28 #include <string.h>
    29 #include <time.h>
    30 
    31 #ifdef __BEOS__
    32     #include <netdb.h>
    33 #endif
    34 
    35 #include <sys/types.h>
    36 
    37 #include "transmission.h"
    38 #include "natpmp.h"
    39 #include "net.h"
    40 #include "platform.h" /* tr_getDefaultRoute() */
    41 #include "utils.h"
    42 
    43 #define PMP_PORT                5351
    44 #define PMP_MCAST_ADDR          "224.0.0.1"
    45 #define PMP_INITIAL_DELAY       250     /* ms, 1/4 second */
    46 #define PMP_TOTAL_DELAY         120000  /* ms, 2 minutes */
    47 #define PMP_VERSION             0
    48 #define PMP_OPCODE_GETIP        0
    49 #define PMP_OPCODE_ADDUDP       1
    50 #define PMP_OPCODE_ADDTCP       2
    51 #define PMP_LIFETIME            3600    /* secs, one hour */
    52 #define PMP_RESULT_OK           0
    53 #define PMP_RESULT_BADVERS      1
    54 #define PMP_RESULT_REFUSED      2
    55 #define PMP_RESULT_NETDOWN      3
    56 #define PMP_RESULT_NOMEM        4
    57 #define PMP_RESULT_BADOPCODE    5
    58 
    59 #define PMP_OPCODE_FROM_RESPONSE( op )  ( 0x80 ^ (op) )
    60 #define PMP_OPCODE_TO_RESPONSE( op )    ( 0x80 | (op) )
    61 #define PMP_OPCODE_IS_RESPONSE( op )    ( 0x80 & (op) )
    62 #define PMP_TOBUF16( buf, num ) ( *( (uint16_t *) (buf) ) = htons( (num) ) )
    63 #define PMP_TOBUF32( buf, num ) ( *( (uint32_t *) (buf) ) = htonl( (num) ) )
    64 #define PMP_FROMBUF16( buf )    ( htons( *( (uint16_t *) (buf) ) ) )
    65 #define PMP_FROMBUF32( buf )    ( htonl( *( (uint32_t *) (buf) ) ) )
    66 
    67 typedef struct tr_natpmp_uptime_s
    68 {
    69     time_t   when;
    70     uint32_t uptime;
    71 } tr_natpmp_uptime_t;
    72 
    73 typedef struct tr_natpmp_req_s
    74 {
    75     unsigned int         adding : 1;
    76     unsigned int         nobodyhome : 1;
    77     unsigned int         tmpfail : 1;
    78     int                  fd;
    79     int                  delay;
    80     uint64_t             retry;
    81     uint64_t             timeout;
    82     int                  askport;
    83     int                  gotport;
    84 } tr_natpmp_req_t;
    85 
    86 struct tr_natpmp
    87 {
    88 #define PMP_STATE_IDLE          1
    89 #define PMP_STATE_ADDING        2
    90 #define PMP_STATE_DELETING      3
    91 #define PMP_STATE_MAPPED        4
    92 #define PMP_STATE_FAILED        5
    93 #define PMP_STATE_NOBODYHOME    6
    94 #define PMP_STATE_TMPFAIL       7
    95     char               state;
    96     unsigned int       active : 1;
    97     unsigned int       mapped : 1;
    98     struct in_addr     dest;
    99     int                newport;
    100     int                mappedport;
    101     uint64_t           renew;
    102     tr_natpmp_req_t *  req;
    103     tr_natpmp_uptime_t uptime;
    104     int                mcastfd;
    105 };
    106 
    107 typedef struct tr_natpmp_parse_s
    108 {
    109     unsigned int tmpfail : 1;
    110     uint32_t     seconds;
    111     uint16_t     port;
    112     uint32_t     lifetime;
    113 }
    114 tr_natpmp_parse_t;
    115 
    116 static void
    117 unmap( tr_natpmp * pmp );
    118 static int
    119 checktime( tr_natpmp_uptime_t * uptime, uint32_t seen );
    120 static void
    121 killsock( int * fd );
    122 static tr_natpmp_req_t *
    123 newreq( int adding, struct in_addr addr, int port );
    124 static void
    125 killreq( tr_natpmp_req_t ** req );
    126 static void
    127 resetreq( tr_natpmp_req_t * req );
    128 static tr_tristate_t
    129 pulsereq( tr_natpmp * req );
    130 static int
    131 sendreq( tr_natpmp_req_t * req );
    132 static int
    133 mcastsetup();
    134 static void
    135 mcastpulse( tr_natpmp * pmp );
    136 static tr_tristate_t
    137 parseresponse( uint8_t * buf, int len, int port, tr_natpmp_parse_t * parse );
    138 
    139 tr_natpmp *
    140 tr_natpmpInit()
    141 {
    142     tr_natpmp * pmp;
    143 
    144     pmp = calloc( 1, sizeof( *pmp ) );
    145     if( NULL == pmp )
    146     {
    147         return NULL;
    148     }
    149 
    150     pmp->state       = PMP_STATE_IDLE;
    151     pmp->mcastfd     = -1;
    152 
    153     if( tr_getDefaultRoute( &pmp->dest ) || INADDR_ANY == pmp->dest.s_addr )
    154     {
    155         pmp->dest.s_addr = INADDR_NONE;
    156     }
    157 
    158     if( INADDR_NONE == pmp->dest.s_addr )
    159     {
    160         tr_dbg( "nat-pmp device is unknown" );
    161     }
    162     else
    163     {
    164         char addrstr[INET_ADDRSTRLEN];
    165         tr_netNtop( &pmp->dest, addrstr, sizeof( addrstr ) );
    166         tr_dbg( "nat-pmp device is %s", addrstr );
    167     }
    168 
    169     return pmp;
    170 }
    171 
    172 void
    173 tr_natpmpStart( tr_natpmp * pmp )
    174 {
    175     if( !pmp->active )
    176     {
    177         tr_inf( "starting nat-pmp" );
    178         pmp->active = 1;
    179         if( 0 > pmp->mcastfd )
    180         {
    181             pmp->mcastfd = mcastsetup();
    182         }
    183     }
    184 }
    185 
    186 void
    187 tr_natpmpStop( tr_natpmp * pmp )
    188 {
    189     if( pmp->active )
    190     {
    191         tr_inf( "stopping nat-pmp" );
    192         pmp->active = 0;
    193         killsock( &pmp->mcastfd );
    194         unmap( pmp );
    195     }
    196 }
    197 
    198 int
    199 tr_natpmpStatus( tr_natpmp * pmp )
    200 {
    201     int ret;
    202    
    203     if( !pmp->active )
    204     {
    205         ret = ( PMP_STATE_DELETING == pmp->state ?
    206                 TR_NAT_TRAVERSAL_UNMAPPING : TR_NAT_TRAVERSAL_DISABLED );
    207     }
    208     else if( pmp->mapped )
    209     {
    210         ret = TR_NAT_TRAVERSAL_MAPPED;
    211     }
    212     else
    213     {
    214         switch( pmp->state )
    215         {
    216             case PMP_STATE_IDLE:
    217             case PMP_STATE_ADDING:
    218             case PMP_STATE_DELETING:
    219                 ret = TR_NAT_TRAVERSAL_MAPPING;
    220                 break;
    221             case PMP_STATE_FAILED:
    222             case PMP_STATE_TMPFAIL:
    223                 ret = TR_NAT_TRAVERSAL_ERROR;
    224                 break;
    225             case PMP_STATE_NOBODYHOME:
    226                 ret = TR_NAT_TRAVERSAL_NOTFOUND;
    227                 break;
    228             case PMP_STATE_MAPPED:
    229             default:
    230                 /* if pmp->state is PMP_STATE_MAPPED then pmp->mapped
    231                    should be true */
    232                 assert( 0 );
    233                 ret = TR_NAT_TRAVERSAL_ERROR;
    234                 break;
    235         }
    236     }
    237 
    238     return ret;
    239 }
    240 
    241 void
    242 tr_natpmpForwardPort( tr_natpmp * pmp, int port )
    243 {
    244     tr_inf( "nat-pmp set port %i", port );
    245     pmp->newport = port;
    246 }
    247 
    248 void
    249 tr_natpmpRemoveForwarding( tr_natpmp * pmp )
    250 {
    251     tr_inf( "nat-pmp unset port" );
    252     pmp->newport = -1;
    253     unmap( pmp );
    254 }
    255 
    256 void
    257 tr_natpmpClose( tr_natpmp * pmp )
    258 {
    259     /* try to send at least one delete request if we have a port mapping */
    260     tr_natpmpStop( pmp );
    261     tr_natpmpPulse( pmp, NULL );
    262 
    263     killreq( &pmp->req );
    264     free( pmp );
    265 }
    266 
    267 void
    268 tr_natpmpPulse( tr_natpmp * pmp, int * publicPort )
    269 {
    270     if( 0 <= pmp->mcastfd )
    271     {
    272         mcastpulse( pmp );
    273     }
    274 
    275     if( NULL != publicPort )
    276     {
    277         *publicPort = -1;
    278     }
    279 
    280     if( pmp->active || PMP_STATE_DELETING == pmp->state )
    281     {
    282         switch( pmp->state )
    283         {
    284             case PMP_STATE_IDLE:
    285             case PMP_STATE_TMPFAIL:
    286                 if( 0 < pmp->newport )
    287                 {
    288                     tr_dbg( "nat-pmp state %s -> add with port %i",
    289                             ( PMP_STATE_IDLE == pmp->state ? "idle" : "err" ),
    290                             pmp->newport );
    291                     pmp->state = PMP_STATE_ADDING;
    292                 }
    293                 break;
    294 
    295             case PMP_STATE_ADDING:
    296                 if( NULL == pmp->req )
    297                 {
    298                     if( 0 >= pmp->newport )
    299                     {
    300                         tr_dbg( "nat-pmp state add -> idle, no port" );
    301                         pmp->state = PMP_STATE_IDLE;
    302                     }
    303                     else if( INADDR_NONE == pmp->dest.s_addr )
    304                     {
    305                         tr_dbg( "nat-pmp state add -> fail, no default route" );
    306                         pmp->state = PMP_STATE_FAILED;
    307                     }
    308                     else
    309                     {
    310                         pmp->req = newreq( 1, pmp->dest, pmp->newport );
    311                         if( NULL == pmp->req )
    312                         {
    313                             pmp->state = PMP_STATE_FAILED;
    314                             tr_dbg( "nat-pmp state add -> fail on req init" );
    315                         }
    316                     }
    317                 }
    318                 if( PMP_STATE_ADDING == pmp->state )
    319                 {
    320                     switch( pulsereq( pmp ) )
    321                     {
    322                         case TR_NET_ERROR:
    323                             if( pmp->req->nobodyhome )
    324                             {
    325                                 pmp->state = PMP_STATE_NOBODYHOME;
    326                                 tr_dbg( "nat-pmp state add -> nobodyhome on pulse" );
    327                             }
    328                             else if( pmp->req->tmpfail )
    329                             {
    330                                 pmp->state = PMP_STATE_TMPFAIL;
    331                                 tr_dbg( "nat-pmp state add -> err on pulse" );
    332                                 if( pmp->req->askport == pmp->newport )
    333                                 {
    334                                     pmp->newport = 0;
    335                                 }
    336                             }
    337                             else
    338                             {
    339                                 pmp->state = PMP_STATE_FAILED;
    340                                 tr_dbg( "nat-pmp state add -> fail on pulse" );
    341                             }
    342                             killreq( &pmp->req );
    343                             break;
    344                         case TR_NET_OK:
    345                             pmp->mappedport = pmp->req->gotport;
    346                             if( pmp->mappedport != pmp->newport &&
    347                                 pmp->newport == pmp->req->askport )
    348                             {
    349                                 pmp->newport = pmp->req->gotport;
    350                             }
    351                             killreq( &pmp->req );
    352                             pmp->state = PMP_STATE_MAPPED;
    353                             pmp->mapped = 1;
    354                             tr_dbg( "nat-pmp state add -> mapped with port %i",
    355                                     pmp->mappedport);
    356                             tr_inf( "nat-pmp mapped port %i", pmp->mappedport );
    357                             if( NULL != publicPort )
    358                             {
    359                                 *publicPort = pmp->mappedport;
    360                             }
    361                             break;
    362                         case TR_NET_WAIT:
    363                             break;
    364                     }
    365                 }
    366                 break;
    367 
    368             case PMP_STATE_DELETING:
    369                 if( NULL == pmp->req )
    370                 {
    371                     assert( 0 < pmp->mappedport );
    372                     pmp->req = newreq( 0, pmp->dest, pmp->mappedport );
    373                     if( NULL == pmp->req )
    374                     {
    375                         pmp->state = PMP_STATE_FAILED;
    376                         tr_dbg( "nat-pmp state del -> fail on req init" );
    377                     }
    378                 }
    379                 if( PMP_STATE_DELETING == pmp->state )
    380                 {
    381                     switch( pulsereq( pmp ) )
    382                     {
    383                         case TR_NET_ERROR:
    384                             if( pmp->req->nobodyhome )
    385                             {
    386                                 pmp->mapped = 0;
    387                                 pmp->state = PMP_STATE_NOBODYHOME;
    388                                 tr_dbg( "nat-pmp state del -> nobodyhome on pulse" );
    389                             }
    390                             else if( pmp->req->tmpfail )
    391                             {
    392                                 pmp->mapped = 0;
    393                                 pmp->state = PMP_STATE_TMPFAIL;
    394                                 tr_dbg( "nat-pmp state del -> err on pulse" );
    395                                 pmp->mappedport = -1;
    396                             }
    397                             else
    398                             {
    399                                 pmp->state = PMP_STATE_FAILED;
    400                                 tr_dbg( "nat-pmp state del -> fail on pulse" );
    401                             }
    402                             killreq( &pmp->req );
    403                             break;
    404                         case TR_NET_OK:
    405                             tr_dbg( "nat-pmp state del -> idle with port %i",
    406                                     pmp->req->askport);
    407                             tr_inf( "nat-pmp unmapped port %i",
    408                                     pmp->req->askport );
    409                             pmp->mapped = 0;
    410                             pmp->mappedport = -1;
    411                             killreq( &pmp->req );
    412                             pmp->state = PMP_STATE_IDLE;
    413                             break;
    414                         case TR_NET_WAIT:
    415                             break;
    416                     }
    417                 }
    418                 break;
    419 
    420             case PMP_STATE_MAPPED:
    421                 if( pmp->newport != pmp->mappedport )
    422                 {
    423                     tr_dbg( "nat-pmp state mapped -> del, port from %i to %i",
    424                             pmp->mappedport, pmp->newport );
    425                     pmp->state = PMP_STATE_DELETING;
    426                 }
    427                 else if( tr_date() > pmp->renew )
    428                 {
    429                     pmp->state = PMP_STATE_ADDING;
    430                     tr_dbg( "nat-pmp state mapped -> add for renewal" );
    431                 }
    432                 break;
    433 
    434             case PMP_STATE_FAILED:
    435             case PMP_STATE_NOBODYHOME:
    436                 break;
    437 
    438             default:
    439                 assert( 0 );
    440                 break;
    441         }
    442     }
    443 }
    444 
    445 void
    446 unmap( tr_natpmp * pmp )
    447 {
    448     switch( pmp->state )
    449     {
    450         case PMP_STATE_IDLE:
    451             break;
    452         case PMP_STATE_ADDING:
    453             if( NULL == pmp->req )
    454             {
    455                 pmp->state = PMP_STATE_IDLE;
    456                 tr_dbg( "nat-pmp state add -> idle" );
    457             }
    458             else
    459             {
    460                 pmp->mappedport = pmp->req->gotport;
    461                 killreq( &pmp->req );
    462                 pmp->state = PMP_STATE_DELETING;
    463                 tr_dbg( "nat-pmp state add -> del" );
    464             }
    465             break;
    466         case PMP_STATE_DELETING:
    467             break;
    468         case PMP_STATE_MAPPED:
    469             pmp->state = PMP_STATE_DELETING;
    470             tr_dbg( "nat-pmp state mapped -> del" );
    471             break;
    472         case PMP_STATE_FAILED:
    473         case PMP_STATE_NOBODYHOME:
    474         case PMP_STATE_TMPFAIL:
    475             break;
    476         default:
    477             assert( 0 );
    478             break;
    479     }
    480 }
    481 
    482 static int
    483 checktime( tr_natpmp_uptime_t * uptime, uint32_t cursecs )
    484 {
    485     time_t   now;
    486     int      ret;
    487     uint32_t estimated;
    488 
    489     now = time( NULL );
    490     ret = 0;
    491     if( 0 < uptime->when )
    492     {
    493         estimated = ( ( now - uptime->when ) * 7 / 8 ) + uptime->uptime;
    494         if( estimated > cursecs )
    495         {
    496             ret = 1;
    497         }
    498     }
    499 
    500     uptime->when   = now;
    501     uptime->uptime = cursecs;
    502 
    503     return ret;
    504 }
    505 
    506 static void
    507 killsock( int * fd )
    508 {
    509     if( 0 <= *fd )
    510     {
    511         tr_netClose( *fd );
    512         *fd = -1;
    513     }
    514 }
    515 
    516 static tr_natpmp_req_t *
    517 newreq( int adding, struct in_addr addr, int port )
    518 {
    519     tr_natpmp_req_t * ret;
    520 
    521     ret = calloc( 1, sizeof( *ret ) );
    522     if( NULL == ret )
    523     {
    524         return NULL;
    525     }
    526 
    527     ret->fd = tr_netOpenUDP( &addr, htons( PMP_PORT ), 1 );
    528     if( 0 > ret->fd )
    529     {
    530         free( ret );
    531         return NULL;
    532     }
    533 
    534     ret->adding  = adding;
    535     ret->askport = port;
    536     ret->gotport = port;
    537     resetreq( ret );
    538     if( sendreq( ret ) )
    539     {
    540         killreq( &ret );
    541         return NULL;
    542     }
    543 
    544     return ret;
    545 }
    546 
    547 static void
    548 killreq( tr_natpmp_req_t ** req )
    549 {
    550     if( NULL != *req )
    551     {
    552         killsock( &(*req)->fd );
    553         free( *req );
    554         *req = NULL;
    555     }
    556 }
    557 
    558 static void
    559 resetreq( tr_natpmp_req_t * req )
    560 {
    561     uint64_t now;
    562 
    563     now          = tr_date();
    564     req->delay   = PMP_INITIAL_DELAY;
    565     req->retry   = now;
    566     req->timeout = now + PMP_TOTAL_DELAY;
    567 }
    568 
    569 static tr_tristate_t
    570 pulsereq( tr_natpmp * pmp )
    571 {
    572     tr_natpmp_req_t  * req = pmp->req;
    573     struct sockaddr_in sin;
    574     uint8_t            buf[16];
    575     int                res;
    576     uint64_t           now;
    577     tr_tristate_t      ret;
    578     tr_natpmp_parse_t  parse;
    579 
    580     now = tr_date();
    581     /* check for timeout */
    582     if( now >= req->timeout )
    583     {
    584         tr_dbg( "nat-pmp request timed out" );
    585         req->nobodyhome = 1;
    586         return TR_NET_ERROR;
    587     }
    588     /* send another request  if it's been long enough */
    589     if( now >= req->retry && sendreq( req ) )
    590     {
    591         return TR_NET_ERROR;
    592     }
    593 
    594     /* check for incoming packets */
    595     res = tr_netRecvFrom( req->fd, buf, sizeof( buf ), &sin );
    596     if( TR_NET_BLOCK & res )
    597     {
    598         return TR_NET_WAIT;
    599     }
    600     else if( TR_NET_CLOSE & res )
    601     {
    602         if( ECONNRESET == sockerrno || ECONNREFUSED == sockerrno )
    603         {
    604             tr_dbg( "nat-pmp not supported by device" );
    605             req->nobodyhome = 1;
    606         }
    607         else
    608         {
    609             tr_inf( "error reading nat-pmp response (%s)", strerror( sockerrno ) );
    610         }
    611         return TR_NET_ERROR;
    612     }
    613 
    614     /* parse the packet */
    615     tr_dbg( "nat-pmp read %i byte response", res );
    616     ret = parseresponse( buf, res, req->askport, &parse );
    617     req->tmpfail = parse.tmpfail;
    618     /* check for device reset */
    619     if( checktime( &pmp->uptime, parse.seconds ) )
    620     {
    621         pmp->renew = 0;
    622         tr_inf( "detected nat-pmp device reset" );
    623         resetreq( req );
    624         ret = TR_NET_WAIT;
    625     }
    626     if( TR_NET_OK == ret && req->adding )
    627     {
    628         if( req->askport != parse.port )
    629         {
    630             tr_dbg( "nat-pmp received %i for public port instead of %i",
    631                     parse.port, req->askport );
    632             req->gotport = parse.port;
    633         }
    634         tr_dbg( "nat-pmp set renew to half of %u", parse.lifetime );
    635         pmp->renew = now + ( parse.lifetime / 2 * 1000 );
    636     }
    637 
    638     return ret;
    639 }
    640 
    641 static int
    642 sendreq( tr_natpmp_req_t * req )
    643 {
    644     uint8_t buf[12];
    645     int res;
    646 
    647     memset( buf, 0, sizeof( buf ) );
    648     buf[0] = PMP_VERSION;
    649     buf[1] = PMP_OPCODE_ADDTCP;
    650     PMP_TOBUF16( buf + 4, req->askport );
    651     if( req->adding )
    652     {
    653         PMP_TOBUF16( buf + 6, req->askport );
    654         PMP_TOBUF32( buf + 8, PMP_LIFETIME );
    655     }
    656 
    657     res = tr_netSend( req->fd, buf, sizeof( buf ) );
    658     if( TR_NET_CLOSE & res && EHOSTUNREACH == sockerrno )
    659     {
    660         res = TR_NET_BLOCK;
    661     }
    662     if( TR_NET_CLOSE & res )
    663     {
    664         tr_err( "failed to send nat-pmp request (%s)", strerror( sockerrno ) );
    665         return 1;
    666     }
    667     else if( !( TR_NET_BLOCK & res ) )
    668     {
    669         /* XXX is it all right to assume the entire thing is written? */
    670         req->retry  = tr_date() + req->delay;
    671         req->delay *= 2;
    672     }
    673     return 0;
    674 }
    675 
    676 static int
    677 mcastsetup()
    678 {
    679     int fd;
    680     struct in_addr addr;
    681 
    682     addr.s_addr = inet_addr( PMP_MCAST_ADDR );
    683     fd = tr_netMcastOpen( PMP_PORT, &addr );
    684     if( 0 > fd )
    685     {
    686         return -1;
    687     }
    688 
    689     tr_dbg( "nat-pmp create multicast socket %i", fd );
    690 
    691     return fd;
    692 }
    693 
    694 static void
    695 mcastpulse( tr_natpmp * pmp )
    696 {
    697     struct sockaddr_in sin;
    698     uint8_t            buf[16];
    699     int                res;
    700     char               dbgstr[INET_ADDRSTRLEN];
    701     tr_natpmp_parse_t  parse;
    702 
    703     res = tr_netRecvFrom( pmp->mcastfd, buf, sizeof( buf ), &sin );
    704     if( TR_NET_BLOCK & res )
    705     {
    706         return;
    707     }
    708     else if( TR_NET_CLOSE & res )
    709     {
    710         tr_err( "error reading nat-pmp multicast message" );
    711         killsock( &pmp->mcastfd );
    712         return;
    713     }
    714 
    715     tr_netNtop( &sin.sin_addr, dbgstr, sizeof( dbgstr ) );
    716     tr_dbg( "nat-pmp read %i byte multicast packet from %s", res, dbgstr );
    717 
    718     if( pmp->dest.s_addr != sin.sin_addr.s_addr )
    719     {
    720         tr_dbg( "nat-pmp ignoring multicast packet from unknown host %s",
    721                 dbgstr );
    722         return;
    723     }
    724 
    725     if( TR_NET_OK == parseresponse( buf, res, -1, &parse ) )
    726     {
    727         if( checktime( &pmp->uptime, parse.seconds ) )
    728         {
    729             pmp->renew = 0;
    730             tr_inf( "detected nat-pmp device reset" );
    731             if( NULL != pmp->req )
    732             {
    733                 resetreq( pmp->req );
    734             }
    735         }
    736         if( PMP_STATE_NOBODYHOME == pmp->state )
    737         {
    738             tr_dbg( "nat-pmp state notfound -> idle" );
    739             pmp->state = PMP_STATE_IDLE;
    740         }
    741     }
    742 }
    743 
    744 static tr_tristate_t
    745 parseresponse( uint8_t * buf, int len, int port, tr_natpmp_parse_t * parse )
    746 {
    747     int version, respopcode, opcode, wantedopcode, rescode, privport;
    748 
    749     memset( parse, 0, sizeof( *parse ) );
    750 
    751     if( 8 > len )
    752     {
    753         tr_err( "read truncated %i byte nat-pmp response packet", len );
    754         return TR_NET_ERROR;
    755     }
    756 
    757     /* parse the first 8 bytes: version, opcode, and result code */
    758     version      = buf[0];
    759     respopcode   = buf[1];
    760     opcode       = PMP_OPCODE_FROM_RESPONSE( respopcode );
    761     wantedopcode = ( 0 < port ? PMP_OPCODE_ADDTCP : PMP_OPCODE_GETIP );
    762     rescode      = PMP_FROMBUF16( buf + 2 );
    763 
    764     if( PMP_VERSION != version )
    765     {
    766         tr_err( "unknown nat-pmp version %hhu", buf[0] );
    767         return TR_NET_ERROR;
    768     }
    769     if( !PMP_OPCODE_IS_RESPONSE( respopcode ) )
    770     {
    771         tr_dbg( "nat-pmp ignoring request packet" );
    772         return TR_NET_WAIT;
    773     }
    774     if( wantedopcode != opcode )
    775     {
    776         tr_err( "unknown nat-pmp opcode %hhu", opcode );
    777         return TR_NET_ERROR;
    778     }
    779 
    780     switch( rescode )
    781     {
    782         case PMP_RESULT_OK:
    783             break;
    784         case PMP_RESULT_REFUSED:
    785             tr_err( "nat-pmp mapping failed: refused/unauthorized/disabled" );
    786             parse->tmpfail = 1;
    787             return TR_NET_ERROR;
    788         case PMP_RESULT_NETDOWN:
    789             tr_err( "nat-pmp mapping failed: network down" );
    790             parse->tmpfail = 1;
    791             return TR_NET_ERROR;
    792         case PMP_RESULT_NOMEM:
    793             tr_err( "nat-pmp mapping refused: insufficient resources" );
    794             parse->tmpfail = 1;
    795             return TR_NET_ERROR;
    796         default:
    797             tr_err( "nat-pmp mapping refused: unknown result code: %hu",
    798                     rescode );
    799             return TR_NET_ERROR;
    800     }
    801 
    802     parse->seconds = PMP_FROMBUF32( buf + 4 );
    803     if( PMP_OPCODE_ADDTCP == opcode )
    804     {
    805         if( 16 > len )
    806         {
    807             tr_err( "read truncated %i byte nat-pmp response packet", len );
    808             return TR_NET_ERROR;
    809         }
    810         privport        = PMP_FROMBUF16( buf + 8 );
    811         parse->port     = PMP_FROMBUF16( buf + 10 );
    812         parse->lifetime = PMP_FROMBUF32( buf + 12 );
    813 
    814         if( port != privport )
    815         {
    816             tr_dbg( "nat-pmp ignoring message for port %i, expected port %i",
    817                     privport, port );
    818             return TR_NET_WAIT;
    819         }
    820     }
    821 
    822     return TR_NET_OK;
    823 }
  • libtransmission/natpmp.h

     
    1 /******************************************************************************
    2  * $Id$
    3  *
    4  * Copyright (c) 2006 Transmission authors and contributors
    5  *
    6  * Permission is hereby granted, free of charge, to any person obtaining a
    7  * copy of this software and associated documentation files (the "Software"),
    8  * to deal in the Software without restriction, including without limitation
    9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
    10  * and/or sell copies of the Software, and to permit persons to whom the
    11  * Software is furnished to do so, subject to the following conditions:
    12  *
    13  * The above copyright notice and this permission notice shall be included in
    14  * all copies or substantial portions of the Software.
    15  *
    16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    22  * DEALINGS IN THE SOFTWARE.
    23  *****************************************************************************/
    24 
    25 #ifndef TR_NATPMP_H
    26 #define TR_NATPMP_H 1
    27 
    28 typedef struct tr_natpmp tr_natpmp;
    29 
    30 tr_natpmp * tr_natpmpInit();
    31 void        tr_natpmpStart( tr_natpmp * );
    32 void        tr_natpmpStop( tr_natpmp * );
    33 int         tr_natpmpStatus( tr_natpmp * );
    34 void        tr_natpmpForwardPort( tr_natpmp *, int );
    35 void        tr_natpmpRemoveForwarding( tr_natpmp * );
    36 void        tr_natpmpPulse( tr_natpmp *, int * );
    37 void        tr_natpmpClose( tr_natpmp * );
    38 
    39 #endif
  • libtransmission/transmission.c

     
    196196    tr_handle * handle = data->handle;
    197197    const int port = data->port;
    198198
     199    tr_sharedSetPort( handle->shared, port );
    199200    handle->isPortSet = 1;
    200     tr_sharedSetPort( handle->shared, port );
    201 
     201   
    202202    tr_free( data );
    203203}
    204204
  • libtransmission/shared.c

     
    3131
    3232#include "transmission.h"
    3333#include "handshake.h"
    34 #include "natpmp.h"
     34#include "nat.h"
    3535#include "net.h"
    3636#include "peer-io.h"
    3737#include "peer-mgr.h"
    3838#include "platform.h"
    3939#include "shared.h"
    4040#include "trevent.h"
    41 #include "upnp.h"
    4241#include "utils.h"
    4342
    4443struct tr_shared
     
    5150    int bindPort;
    5251    int bindSocket;
    5352
    54     /* NAT-PMP/UPnP */
    55     tr_natpmp  * natpmp;
    56     tr_upnp    * upnp;
     53    /* NAT-Traversal */
     54    tr_nat  * nat;
    5755};
    5856
    5957/***********************************************************************
     
    7775    s->publicPort = -1;
    7876    s->bindPort   = -1;
    7977    s->bindSocket = -1;
    80     s->natpmp     = tr_natpmpInit();
    81     s->upnp       = tr_upnpInit();
     78    s->nat        = tr_natInit( h );
    8279    s->pulseTimer   = tr_timerNew( h, SharedLoop, s, 500 );
    8380
    8481    return s;
     
    9491    tr_timerFree( &s->pulseTimer );
    9592
    9693    tr_netClose( s->bindSocket );
    97     tr_natpmpClose( s->natpmp );
    98     tr_upnpClose( s->upnp );
     94    tr_natClose( s->nat );
    9995    free( s );
    10096}
    10197
     
    119115        tr_globalUnlock( s->h );
    120116        return;
    121117    }
     118    int oldPort = s->bindPort;
     119   
    122120    s->bindPort = port;
    123121
    124122    /* Close the previous accept socket, if any */
     
    137135    if( s->bindSocket < 0 )
    138136    {
    139137        /* Remove the forwarding for the old port */
    140         tr_natpmpRemoveForwarding( s->natpmp );
    141         tr_upnpRemoveForwarding( s->upnp );
     138        tr_natCancelPort( s->nat, oldPort, TR_TCP_PORT );
    142139    }
    143140    else
    144141    {
    145142        tr_inf( "Bound listening port %d", port );
    146143        listen( s->bindSocket, 5 );
    147144        /* Forward the new port */
    148         tr_natpmpForwardPort( s->natpmp, port );
    149         tr_upnpForwardPort( s->upnp, port );
     145        tr_natForwardPort( s->nat, port, TR_TCP_PORT );
    150146    }
    151147
    152148    tr_globalUnlock( s->h );
     
    167163{
    168164    if( enable )
    169165    {
    170         tr_natpmpStart( s->natpmp );
    171         tr_upnpStart( s->upnp );
     166        tr_natStart( s->nat );
    172167    }
    173168    else
    174169    {
    175         tr_natpmpStop( s->natpmp );
    176         tr_upnpStop( s->upnp );
     170        tr_natStop( s->nat );
    177171    }
    178172}
    179173
    180174int tr_sharedTraversalStatus( const tr_shared * s )
    181175{
    182     const int statuses[] = {
    183         TR_NAT_TRAVERSAL_MAPPED,
    184         TR_NAT_TRAVERSAL_MAPPING,
    185         TR_NAT_TRAVERSAL_UNMAPPING,
    186         TR_NAT_TRAVERSAL_ERROR,
    187         TR_NAT_TRAVERSAL_NOTFOUND,
    188         TR_NAT_TRAVERSAL_DISABLED,
    189         -1,
    190     };
    191     int natpmp, upnp, ii;
     176    return tr_natStatusForPort( s->nat, s->publicPort, TR_TCP_PORT );
    192177
    193     natpmp = tr_natpmpStatus( s->natpmp );
    194     upnp = tr_upnpStatus( s->upnp );
    195 
    196     for( ii = 0; 0 <= statuses[ii]; ii++ )
    197     {
    198         if( statuses[ii] == natpmp || statuses[ii] == upnp )
    199         {
    200             return statuses[ii];
    201         }
    202     }
    203 
    204     assert( 0 );
    205 
    206     return TR_NAT_TRAVERSAL_ERROR;
    207 
    208178}
    209179
    210180
     
    223193
    224194    tr_globalLock( s->h );
    225195
    226     /* NAT-PMP and UPnP pulses */
    227     newPort = -1;
    228     tr_natpmpPulse( s->natpmp, &newPort );
    229     if( 0 < newPort && newPort != s->publicPort )
    230         SetPublicPort( s, newPort );
    231     tr_upnpPulse( s->upnp );
     196    /* NAT-Traversal pulses */
     197    tr_natPulse( s->nat );
    232198
    233199    /* Handle incoming connections */
    234200    AcceptPeers( s );
  • libtransmission/nat.c

     
     1/*
     2 * This file Copyright (C) 2007 Charles Kerr <charles@rebelbase.com>
     3 *
     4 * This file is licensed by the GPL version 2.  Works owned by the
     5 * Transmission project are granted a special exemption to clause 2(b)
     6 * so that the bulk of its code can remain under the MIT license.
     7 * This exemption does not extend to derived works not owned by
     8 * the Transmission project.
     9 *
     10 * $Id$
     11 */
     12
     13/* TODO :
     14 * - Implement some kind of pulsating refresh, using NAT-PMP epoch and UPnP *nothing* ;-)
     15 * - Add ability to portmap without a NAT device discovered, and map port after discovery
     16 *
     17 * - Check UPnP error codes. This depends mainly on miniupnp ability to return error codes.
     18 *
     19 * - Check NAT-PMP epoch, so that we learn about gateway reboots to remap all our ports.
     20 */
     21
     22#include <assert.h>
     23#include <miniupnp/miniupnpc.h>
     24#include <pmpmyapp/pmpmapper.h>
     25
     26#include "transmission.h"
     27#include "internal.h"
     28#include "list.h"
     29#include "net.h"
     30#include "utils.h"
     31
     32#include "nat.h"
     33
     34struct _nat_port
     35{
     36    int port;
     37    tr_natPortType type;
     38};
     39
     40int
     41natPortCmp(const void * a, const void * b)
     42{
     43    const struct _nat_port * sA = a;
     44    const struct _nat_port * sB = a;
     45   
     46    if( sA->port != sB->port )
     47        return ( sA->port < sB->port ?  1 : -1 );
     48   
     49    if( sA->type != sB->type )
     50        return ( sA->type < sB->type ?  1 : -1 );
     51   
     52    return 0;
     53}
     54
     55struct _tr_nat
     56{
     57    tr_list       * ports;
     58    unsigned int    isEnabled : 1;
     59    int             hasDiscoveredUPnP;      /* -1 : Unknown, 0 : Not Found / Error, 1 : Found */
     60    int             hasDiscoveredNATPMP;    /* -1 : Unknown, 0 : Not Found / Error, 1 : Found */
     61    tr_handle     * handle;
     62   
     63    /* UPnP specific stuff */
     64    char lanaddr[16];
     65    struct UPNPUrls urls;
     66    struct IGDdatas data;
     67};
     68
     69tr_nat *
     70tr_natInit( tr_handle * handle )
     71{
     72    tr_nat * ret = tr_new0( tr_nat, 1 );
     73    if( ret == NULL )
     74        return NULL;
     75   
     76    ret->handle = handle;
     77    ret->ports = NULL;
     78    ret->hasDiscoveredUPnP = -1;
     79    ret->hasDiscoveredNATPMP = -1;
     80    return ret;
     81}
     82
     83void
     84tr_natClose( tr_nat * nat )
     85{
     86    tr_natCancelAllPorts( nat );
     87    tr_list_free( &nat->ports, tr_free );
     88    tr_free( nat );
     89}
     90
     91static void
     92discoverUPNPDevice( void * vdata );
     93
     94static void
     95discoverNATPMPDevice( void * vdata );
     96
     97int
     98tr_natStart( tr_nat * handle )
     99{
     100    if( handle->hasDiscoveredUPnP == -1 )
     101    {
     102        tr_runInEventThread( handle->handle, discoverUPNPDevice, handle );
     103    }
     104   
     105    if( handle->hasDiscoveredNATPMP == -1 )
     106    {
     107        tr_runInEventThread( handle->handle, discoverNATPMPDevice, handle );
     108    }
     109   
     110    handle->isEnabled = 1;
     111    return handle->hasDiscoveredUPnP || handle->hasDiscoveredNATPMP;
     112}
     113
     114int
     115tr_natStop( tr_nat * nat )
     116{
     117    tr_natCancelAllPorts( nat );
     118   
     119    nat->isEnabled = 0;
     120   
     121    return 0;
     122}
     123
     124int
     125tr_natStatus( tr_nat * nat )
     126{
     127    if( nat->isEnabled == 0 )
     128        return TR_NAT_TRAVERSAL_DISABLED;
     129   
     130    if( nat->hasDiscoveredUPnP == 0 && nat->hasDiscoveredNATPMP == 0 )
     131        return TR_NAT_TRAVERSAL_ERROR;
     132   
     133    return 0;
     134}
     135
     136int
     137tr_natStatusForPort( tr_nat * nat, int port, tr_natPortType type )
     138{
     139    int err = tr_natStatus( nat );
     140    if( err != 0 )
     141        return err;
     142   
     143    struct _nat_port portMap;
     144    portMap.port = port;
     145    portMap.type = type;
     146   
     147    tr_list * item = tr_list_find( nat->ports, &portMap, natPortCmp );
     148    if( item == NULL )
     149        return TR_NAT_TRAVERSAL_NOTFOUND;
     150   
     151    return TR_NAT_TRAVERSAL_MAPPED;
     152}
     153
     154int
     155tr_natForwardPort( tr_nat * handle, int port, tr_natPortType portType )
     156{
     157    int upnpErr = 0;
     158    int natpmpErr = 0;
     159   
     160    struct _nat_port * portMap = tr_new( struct _nat_port, 1 );
     161    portMap->port = port;
     162    portMap->type = portType;
     163   
     164    if( handle->isEnabled == 0 )
     165        return TR_NAT_TRAVERSAL_DISABLED;
     166   
     167    if( handle->hasDiscoveredUPnP != 1 && handle->hasDiscoveredNATPMP != 1 )
     168        return TR_NAT_TRAVERSAL_NOTFOUND;
     169   
     170    if( handle->hasDiscoveredUPnP == 1 )
     171    {
     172        char portStr[16];
     173        snprintf( portStr, sizeof(portStr), "%d", port );
     174       
     175       
     176        upnpErr = UPNP_AddPortMapping( handle->urls.controlURL,
     177                                      handle->data.servicetype,
     178                                      portStr, portStr, handle->lanaddr,
     179                                      "Transmission",
     180                                      ( portType == TR_TCP_PORT ? "TCP" : "UDP" )
     181                                      );
     182        if( upnpErr != 0 )
     183            tr_err( "UPnP Port Forwarding via '%s', service '%s' (local address: %s:%d) failed",
     184                   handle->urls.controlURL, handle->data.servicetype, upnpErr, handle->lanaddr, port );
     185        else
     186            tr_dbg( "UPNP Port Forwarding via '%s', service '%s' returned %d (local address: %s:%d)",
     187                   handle->urls.controlURL, handle->data.servicetype, upnpErr, handle->lanaddr, port );
     188    }
     189   
     190    if( handle->hasDiscoveredNATPMP == 1 )
     191    {
     192        natpmpErr = pmp_create_map( portType, port, port, PMP_LIFETIME ) != NULL;
     193        if( natpmpErr != 0 )
     194        {
     195            tr_err( "NAT-PMP Port Forwarding %s port %d failed", ( portType == 1 ? "TCP" : "UDP" ), port );
     196        }
     197        else
     198        {
     199            tr_dbg( "NAT-PMP Port Forwarding %s port %d", ( portType == 1 ? "TCP" : "UDP" ), port );
     200        }
     201    }
     202   
     203    if( ( handle->hasDiscoveredUPnP == 1 && upnpErr != 0 )
     204       || ( handle->hasDiscoveredNATPMP == 1 && natpmpErr != 0 ) )
     205    {
     206        /* It failed */
     207        return TR_NAT_TRAVERSAL_ERROR;
     208    }
     209   
     210    /* We successfully mapped this port, either with UPnP or NAT-PMP,
     211     * add it to the list of mapped ports */
     212    tr_list_append( &handle->ports, portMap );
     213    return TR_NAT_TRAVERSAL_MAPPED;
     214}
     215
     216int
     217tr_natCancelPort( tr_nat * handle, int port, tr_natPortType portType )
     218{
     219    if( handle->isEnabled == 0 )
     220        return TR_NAT_TRAVERSAL_DISABLED;
     221   
     222    if( handle->hasDiscoveredUPnP != 1 && handle->hasDiscoveredNATPMP != 1 )
     223        return TR_NAT_TRAVERSAL_NOTFOUND;
     224   
     225    int upnpErr = 0;
     226    int natpmpErr = 0;
     227   
     228    struct _nat_port portMap;
     229    portMap.port = port;
     230    portMap.type = portType;
     231   
     232    tr_list * item = tr_list_find( handle->ports, &portMap, natPortCmp );
     233    if( item == NULL )
     234        return -1;
     235   
     236    if( handle->hasDiscoveredUPnP == 1 )
     237    {
     238        char portStr[16];
     239        snprintf( portStr, sizeof(portStr), "%d", port );
     240       
     241        upnpErr = UPNP_DeletePortMapping( handle->urls.controlURL,
     242                                         handle->data.servicetype,
     243                                         portStr, ( portType == TR_TCP_PORT ? "TCP" : "UDP" )
     244                                         );
     245       
     246        if( upnpErr != 0 )
     247            tr_err( "UPnP unmapping port forwarding on '%s', service '%s' failed",
     248                   handle->urls.controlURL, handle->data.servicetype );
     249        else
     250            tr_dbg( "UPnP unmapping port forwarding on '%s', service '%s' successful",
     251                   handle->urls.controlURL, handle->data.servicetype );
     252    }
     253   
     254    if( handle->hasDiscoveredNATPMP == 1 )
     255    {
     256        natpmpErr = pmp_destroy_map( portType, port ) != NULL;
     257        if( natpmpErr != 0)
     258        {
     259            tr_err( "NAT-PMP Unmapping %s port %d failed", ( portType == 1 ? "TCP" : "UDP" ), port );
     260        }
     261        else
     262        {
     263            tr_dbg( "NAT-PMP Unmapping %s port %d successful", ( portType == 1 ? "TCP" : "UDP" ), port );
     264        }
     265       
     266    }
     267   
     268    /* Remove this portmap from our list */
     269    tr_list_remove_data( &handle->ports, item->data );
     270   
     271    return 0;
     272}
     273
     274void
     275tr_natCancelAllPorts( tr_nat * handle )
     276{
     277    assert( handle != NULL );
     278   
     279    while( handle->ports != NULL )
     280    {
     281        struct _nat_port * item = handle->ports->data;
     282        tr_natCancelPort( handle, item->port, item->type );
     283    }
     284}
     285
     286void
     287tr_natPulse( tr_nat * nat )
     288{
     289   
     290}
     291
     292static void
     293discoverNATPMPDevice( void * vdata )
     294{
     295    tr_nat * handle = vdata;
     296    struct sockaddr_in * addr = pmp_get_public();
     297   
     298    if( addr != NULL )
     299    {
     300        tr_dbg( "Found NAT-PMP device at address %s", inet_ntoa( addr->sin_addr ) );
     301        handle->hasDiscoveredNATPMP = 1;
     302    }
     303    else
     304    {
     305        tr_err( "Gateway isn't NAT-PMP enabled, or error while discovering." );
     306        handle->hasDiscoveredNATPMP = 0;
     307    }
     308}
     309
     310
     311static void
     312discoverUPNPDevice( void * vdata )
     313{
     314    tr_nat * handle = vdata;
     315    struct UPNPDev * devlist = upnpDiscover( 2000, NULL );
     316   
     317    int err = UPNP_GetValidIGD( devlist, &handle->urls, &handle->data, handle->lanaddr, sizeof(handle->lanaddr));
     318    switch (err) {
     319        case 0:
     320            tr_dbg( "No Internet Gateway Device found." );
     321            handle->hasDiscoveredUPnP = 0;
     322            break;
     323        case 1:
     324            tr_dbg( "Found Internet Gateway Device '%s'", handle->urls.controlURL );
     325            tr_dbg( "Local LAN IP Address is '%s'", handle->lanaddr );
     326            handle->hasDiscoveredUPnP = 1;
     327            freeUPNPDevlist( devlist );
     328            break;
     329        case 2:
     330            tr_dbg( "Found Internet Gateway Device '%s', but it reported being disconnected", handle->urls.controlURL );
     331            tr_dbg( "Local LAN IP Address is '%s'", handle->lanaddr );
     332            handle->hasDiscoveredUPnP = 1;
     333            freeUPNPDevlist( devlist );
     334            break;
     335        case 3:
     336            tr_dbg( "Found Internet Gateway Device '%s', but it wasn't recognized", handle->urls.controlURL );
     337            tr_dbg( "Local LAN IP Address is '%s'", handle->lanaddr );
     338            handle->hasDiscoveredUPnP = 1;
     339            freeUPNPDevlist( devlist );
     340            break;
     341        default:
     342            break;
     343    }
     344}
     345 No newline at end of file
  • libtransmission/upnp.c

     
    1 /*
    2  * This file Copyright (C) 2007 Charles Kerr <charles@rebelbase.com>
    3  *
    4  * This file is licensed by the GPL version 2.  Works owned by the
    5  * Transmission project are granted a special exemption to clause 2(b)
    6  * so that the bulk of its code can remain under the MIT license.
    7  * This exemption does not extend to derived works not owned by
    8  * the Transmission project.
    9  *
    10  * $Id$
    11  */
    12 
    13 #include <stdio.h> /* printf */
    14 
    15 #include <miniupnp/miniwget.h>
    16 #include <miniupnp/miniupnpc.h>
    17 #include <miniupnp/upnpcommands.h>
    18 
    19 #include "transmission.h"
    20 #include "internal.h"
    21 #include "utils.h"
    22 #include "upnp.h"
    23 
    24 struct tr_upnp
    25 {
    26     struct UPNPUrls urls;
    27     struct IGDdatas data;
    28     int port;
    29     char lanaddr[16];
    30     unsigned int isForwarding : 1;
    31     unsigned int isEnabled : 1;
    32     unsigned int hasDiscovered : 1;
    33 };
    34 
    35 /**
    36 ***
    37 **/
    38 
    39 tr_upnp*
    40 tr_upnpInit( void )
    41 {
    42     tr_upnp * ret = tr_new0( tr_upnp, 1 );
    43     ret->port = -1;
    44     return ret;
    45 }
    46 
    47 void
    48 tr_upnpClose( tr_upnp * handle )
    49 {
    50     tr_upnpStop( handle );
    51     if( handle->hasDiscovered )
    52         FreeUPNPUrls( &handle->urls );
    53     tr_free( handle );
    54 }
    55 
    56 /**
    57 ***
    58 **/
    59 
    60 void
    61 tr_upnpStart( tr_upnp * handle )
    62 {
    63     if( !handle->hasDiscovered )
    64     {
    65         struct UPNPDev * devlist = upnpDiscover( 2000, NULL );
    66         if( UPNP_GetValidIGD( devlist, &handle->urls, &handle->data, handle->lanaddr, sizeof(handle->lanaddr))) {
    67             tr_dbg( "UPNP: Found Internet Gateway Device '%s'", handle->urls.controlURL );
    68             tr_dbg( "UPNP: Local LAN IP Address is '%s'", handle->lanaddr );
    69         }
    70         freeUPNPDevlist( devlist );
    71         handle->hasDiscovered = 1;
    72     }
    73 
    74     handle->isEnabled = 1;
    75 
    76     if( handle->port >= 0 )
    77     {
    78         char portStr[16];
    79         snprintf( portStr, sizeof(portStr), "%d", handle->port );
    80         handle->isForwarding = ( handle->urls.controlURL != NULL ) &&
    81                                ( handle->data.servicetype != NULL ) &&
    82                                ( UPNP_AddPortMapping( handle->urls.controlURL,
    83                                                       handle->data.servicetype,
    84                                                       portStr, portStr, handle->lanaddr,
    85                                                       "Transmission", "TCP" ) );
    86 
    87         tr_inf( "UPNP: Port Forwarding via '%s', service '%s'.  (local address: %s:%d)",
    88                 handle->urls.controlURL, handle->data.servicetype, handle->lanaddr, handle->port );
    89         tr_inf( "UPNP: Port Forwarding Enabled?  %s", (handle->isForwarding?"Yes":"No") );
    90     }
    91 }
    92 
    93 void
    94 tr_upnpRemoveForwarding ( tr_upnp * handle )
    95 {
    96     handle->port = -1;
    97 
    98     if( handle->isForwarding )
    99     {
    100         char portStr[16];
    101         snprintf( portStr, sizeof(portStr), "%d", handle->port );
    102 
    103         UPNP_DeletePortMapping( handle->urls.controlURL,
    104                                 handle->data.servicetype,
    105                                 portStr, "TCP" );
    106         tr_dbg( "Stopping port forwarding of '%s', service '%s'",
    107                 handle->urls.controlURL, handle->data.servicetype );
    108 
    109         handle->isForwarding = FALSE;
    110     }
    111 }
    112 
    113 void
    114 tr_upnpForwardPort( tr_upnp * handle, int publicPort )
    115 {
    116     tr_upnpRemoveForwarding( handle ); /* remove the old forwarding */
    117 
    118     handle->port = publicPort;
    119 
    120     if( handle->isEnabled )
    121         tr_upnpStart( handle );
    122 }
    123 
    124 void
    125 tr_upnpStop( tr_upnp * handle )
    126 {
    127     tr_upnpRemoveForwarding( handle );
    128     handle->isEnabled = 0;
    129 }
    130 
    131 int
    132 tr_upnpStatus( tr_upnp * handle )
    133 {
    134     if( !handle->isEnabled )
    135         return TR_NAT_TRAVERSAL_DISABLED;
    136 
    137     if( !handle->isForwarding )
    138         return TR_NAT_TRAVERSAL_ERROR;
    139 
    140     return TR_NAT_TRAVERSAL_MAPPED;
    141 }
    142 
    143 void
    144 tr_upnpPulse( tr_upnp * handle UNUSED )
    145 {
    146     /* no-op */
    147 }
  • libtransmission/nat.h

     
     1/*
     2 * This file Copyright (C) 2007 Charles Kerr <charles@rebelbase.com>
     3 *
     4 * This file is licensed by the GPL version 2.  Works owned by the
     5 * Transmission project are granted a special exemption to clause 2(b)
     6 * so that the bulk of its code can remain under the MIT license.
     7 * This exemption does not extend to derived works not owned by
     8 * the Transmission project.
     9 *
     10 * $Id$
     11 */
     12
     13#ifndef TR_NAT_H
     14#define TR_NAT_H 1
     15
     16typedef struct _tr_nat tr_nat;
     17
     18typedef enum {
     19    TR_TCP_PORT = 1,
     20    TR_UDP_PORT = 2
     21} tr_natPortType;
     22
     23tr_nat *
     24tr_natInit( tr_handle * handle );
     25
     26void
     27tr_natClose( tr_nat * nat );
     28
     29int
     30tr_natStart( tr_nat * nat );
     31
     32int
     33tr_natStop( tr_nat * nat );
     34
     35int
     36tr_natStatus( tr_nat * nat );
     37
     38int
     39tr_natForwardPort( tr_nat * nat, int port, tr_natPortType portType );
     40
     41int
     42tr_natCancelPort( tr_nat * nat, int port, tr_natPortType portType );
     43
     44void
     45tr_natCancelAllPorts( tr_nat * nat );
     46
     47void
     48tr_natPulse( tr_nat * nat );
     49
     50#endif /* TR_NAT_H */
     51 No newline at end of file
  • libtransmission/upnp.h

     
    1 /******************************************************************************
    2  * $Id$
    3  *
    4  * Copyright (c) 2006 Transmission authors and contributors
    5  *
    6  * Permission is hereby granted, free of charge, to any person obtaining a
    7  * copy of this software and associated documentation files (the "Software"),
    8  * to deal in the Software without restriction, including without limitation
    9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
    10  * and/or sell copies of the Software, and to permit persons to whom the
    11  * Software is furnished to do so, subject to the following conditions:
    12  *
    13  * The above copyright notice and this permission notice shall be included in
    14  * all copies or substantial portions of the Software.
    15  *
    16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    22  * DEALINGS IN THE SOFTWARE.
    23  *****************************************************************************/
    24 
    25 #ifndef TR_UPNP_H
    26 #define TR_UPNP_H 1
    27 
    28 typedef struct tr_upnp tr_upnp;
    29 
    30 tr_upnp * tr_upnpInit             ( void );
    31 void      tr_upnpStart            ( tr_upnp * );
    32 void      tr_upnpStop             ( tr_upnp * );
    33 int       tr_upnpStatus           ( tr_upnp * );
    34 void      tr_upnpForwardPort      ( tr_upnp *, int );
    35 void      tr_upnpRemoveForwarding ( tr_upnp * );
    36 void      tr_upnpPulse            ( tr_upnp * );
    37 void      tr_upnpClose            ( tr_upnp * );
    38 
    39 #endif
  • Transmission.xcodeproj/project.pbxproj

     
    1717                4D118E1A08CB46B20033958F /* PrefsController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D118E1908CB46B20033958F /* PrefsController.m */; };
    1818                4D1838DD09DEC0E80047D688 /* libtransmission.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D18389709DEC0030047D688 /* libtransmission.a */; };
    1919                4D364DA0091FBB2C00377D12 /* TorrentTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D364D9F091FBB2C00377D12 /* TorrentTableView.m */; };
     20                4D3695400CE8FD6800D781A9 /* nat.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D36953E0CE8FD6800D781A9 /* nat.c */; };
     21                4D3695410CE8FD6800D781A9 /* nat.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D36953F0CE8FD6800D781A9 /* nat.h */; };
    2022                4D36BA6F0CA2F00800A63CA5 /* crypto.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D36BA600CA2F00800A63CA5 /* crypto.c */; };
    2123                4D36BA700CA2F00800A63CA5 /* crypto.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D36BA610CA2F00800A63CA5 /* crypto.h */; };
    2224                4D36BA720CA2F00800A63CA5 /* handshake.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D36BA630CA2F00800A63CA5 /* handshake.c */; };
     
    5254                4DE5CCBA0981D27700BE280E /* ResumeAll.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DE5CCB80981D27700BE280E /* ResumeAll.png */; };
    5355                4DE5CCBB0981D27700BE280E /* PauseAll.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DE5CCB90981D27700BE280E /* PauseAll.png */; };
    5456                4DE5CCCB0981D9BE00BE280E /* Defaults.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4DE5CCCA0981D9BE00BE280E /* Defaults.plist */; };
     57                4DEFE48A0CFC727A001D335E /* pmpmapper.c in Sources */ = {isa = PBXBuildFile; fileRef = 4DEFE4880CFC727A001D335E /* pmpmapper.c */; };
     58                4DEFE48B0CFC727A001D335E /* pmpmapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DEFE4890CFC727A001D335E /* pmpmapper.h */; };
     59                4DEFE4D40CFC821C001D335E /* route.c in Sources */ = {isa = PBXBuildFile; fileRef = 4DEFE4D20CFC821C001D335E /* route.c */; };
     60                4DEFE4D50CFC821C001D335E /* route.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DEFE4D30CFC821C001D335E /* route.h */; };
     61                4DEFE5040CFC8BC5001D335E /* libpmpmyapp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4DEFE4840CFC7269001D335E /* libpmpmyapp.a */; };
    5562                4DF0C5AB0899190500DD8943 /* Controller.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DF0C5A90899190500DD8943 /* Controller.m */; };
    5663                4DF7500C08A103AD007B0D70 /* Open.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DF7500708A103AD007B0D70 /* Open.png */; };
    5764                4DF7500D08A103AD007B0D70 /* Info.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DF7500808A103AD007B0D70 /* Info.png */; };
     
    210217                BEFC1E290C07861A00B0BB3C /* version.h in Headers */ = {isa = PBXBuildFile; fileRef = BEFC1DF00C07861A00B0BB3C /* version.h */; };
    211218                BEFC1E2A0C07861A00B0BB3C /* utils.h in Headers */ = {isa = PBXBuildFile; fileRef = BEFC1DF10C07861A00B0BB3C /* utils.h */; };
    212219                BEFC1E2B0C07861A00B0BB3C /* utils.c in Sources */ = {isa = PBXBuildFile; fileRef = BEFC1DF20C07861A00B0BB3C /* utils.c */; };
    213                 BEFC1E2C0C07861A00B0BB3C /* upnp.h in Headers */ = {isa = PBXBuildFile; fileRef = BEFC1DF30C07861A00B0BB3C /* upnp.h */; };
    214                 BEFC1E2D0C07861A00B0BB3C /* upnp.c in Sources */ = {isa = PBXBuildFile; fileRef = BEFC1DF40C07861A00B0BB3C /* upnp.c */; };
    215220                BEFC1E2E0C07861A00B0BB3C /* transmission.h in Headers */ = {isa = PBXBuildFile; fileRef = BEFC1DF50C07861A00B0BB3C /* transmission.h */; };
    216221                BEFC1E2F0C07861A00B0BB3C /* transmission.c in Sources */ = {isa = PBXBuildFile; fileRef = BEFC1DF60C07861A00B0BB3C /* transmission.c */; };
    217222                BEFC1E300C07861A00B0BB3C /* tracker.h in Headers */ = {isa = PBXBuildFile; fileRef = BEFC1DF70C07861A00B0BB3C /* tracker.h */; };
     
    225230                BEFC1E3C0C07861A00B0BB3C /* platform.c in Sources */ = {isa = PBXBuildFile; fileRef = BEFC1E030C07861A00B0BB3C /* platform.c */; };
    226231                BEFC1E450C07861A00B0BB3C /* net.h in Headers */ = {isa = PBXBuildFile; fileRef = BEFC1E0C0C07861A00B0BB3C /* net.h */; };
    227232                BEFC1E460C07861A00B0BB3C /* net.c in Sources */ = {isa = PBXBuildFile; fileRef = BEFC1E0D0C07861A00B0BB3C /* net.c */; };
    228                 BEFC1E470C07861A00B0BB3C /* natpmp.h in Headers */ = {isa = PBXBuildFile; fileRef = BEFC1E0E0C07861A00B0BB3C /* natpmp.h */; };
    229                 BEFC1E480C07861A00B0BB3C /* natpmp.c in Sources */ = {isa = PBXBuildFile; fileRef = BEFC1E0F0C07861A00B0BB3C /* natpmp.c */; };
    230233                BEFC1E490C07861A00B0BB3C /* metainfo.h in Headers */ = {isa = PBXBuildFile; fileRef = BEFC1E100C07861A00B0BB3C /* metainfo.h */; };
    231234                BEFC1E4A0C07861A00B0BB3C /* metainfo.c in Sources */ = {isa = PBXBuildFile; fileRef = BEFC1E110C07861A00B0BB3C /* metainfo.c */; };
    232235                BEFC1E4B0C07861A00B0BB3C /* ipcparse.h in Headers */ = {isa = PBXBuildFile; fileRef = BEFC1E120C07861A00B0BB3C /* ipcparse.h */; };
     
    266269                        remoteGlobalIDString = 4D18389609DEC0030047D688;
    267270                        remoteInfo = libtransmission;
    268271                };
     272                4DEFE48F0CFC7334001D335E /* PBXContainerItemProxy */ = {
     273                        isa = PBXContainerItemProxy;
     274                        containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
     275                        proxyType = 1;
     276                        remoteGlobalIDString = 4DEFE4830CFC7269001D335E /* pmpmyapp */;
     277                        remoteInfo = pmpmyapp;
     278                };
    269279                BE1183750CE161040002D0F3 /* PBXContainerItemProxy */ = {
    270280                        isa = PBXContainerItemProxy;
    271281                        containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
     
    339349                4D2784360905709500687951 /* Transmission.icns */ = {isa = PBXFileReference; explicitFileType = image.icns; name = Transmission.icns; path = macosx/Images/Transmission.icns; sourceTree = "<group>"; };
    340350                4D364D9E091FBB2C00377D12 /* TorrentTableView.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = TorrentTableView.h; path = macosx/TorrentTableView.h; sourceTree = "<group>"; };
    341351                4D364D9F091FBB2C00377D12 /* TorrentTableView.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; name = TorrentTableView.m; path = macosx/TorrentTableView.m; sourceTree = "<group>"; };
     352                4D36953E0CE8FD6800D781A9 /* nat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = nat.c; path = libtransmission/nat.c; sourceTree = "<group>"; };
     353                4D36953F0CE8FD6800D781A9 /* nat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = nat.h; path = libtransmission/nat.h; sourceTree = "<group>"; };
    342354                4D36BA600CA2F00800A63CA5 /* crypto.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = crypto.c; path = libtransmission/crypto.c; sourceTree = "<group>"; };
    343355                4D36BA610CA2F00800A63CA5 /* crypto.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = crypto.h; path = libtransmission/crypto.h; sourceTree = "<group>"; };
    344356                4D36BA630CA2F00800A63CA5 /* handshake.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = handshake.c; path = libtransmission/handshake.c; sourceTree = "<group>"; };
     
    375387                4DE5CCB80981D27700BE280E /* ResumeAll.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ResumeAll.png; path = macosx/Images/ResumeAll.png; sourceTree = "<group>"; };
    376388                4DE5CCB90981D27700BE280E /* PauseAll.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = PauseAll.png; path = macosx/Images/PauseAll.png; sourceTree = "<group>"; };
    377389                4DE5CCCA0981D9BE00BE280E /* Defaults.plist */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xml; name = Defaults.plist; path = macosx/Defaults.plist; sourceTree = "<group>"; };
     390                4DEFE4840CFC7269001D335E /* libpmpmyapp.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libpmpmyapp.a; sourceTree = BUILT_PRODUCTS_DIR; };
     391                4DEFE4880CFC727A001D335E /* pmpmapper.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pmpmapper.c; sourceTree = "<group>"; };
     392                4DEFE4890CFC727A001D335E /* pmpmapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pmpmapper.h; sourceTree = "<group>"; };
     393                4DEFE4D20CFC821C001D335E /* route.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = route.c; sourceTree = "<group>"; };
     394                4DEFE4D30CFC821C001D335E /* route.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = route.h; sourceTree = "<group>"; };
    378395                4DF0C5A90899190500DD8943 /* Controller.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; name = Controller.m; path = macosx/Controller.m; sourceTree = "<group>"; };
    379396                4DF0C5AA0899190500DD8943 /* Controller.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Controller.h; path = macosx/Controller.h; sourceTree = "<group>"; };
    380397                4DF7500708A103AD007B0D70 /* Open.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Open.png; path = macosx/Images/Open.png; sourceTree = "<group>"; };
     
    604621                BEFC1DF00C07861A00B0BB3C /* version.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = version.h; path = libtransmission/version.h; sourceTree = "<group>"; };
    605622                BEFC1DF10C07861A00B0BB3C /* utils.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = utils.h; path = libtransmission/utils.h; sourceTree = "<group>"; };
    606623                BEFC1DF20C07861A00B0BB3C /* utils.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = utils.c; path = libtransmission/utils.c; sourceTree = "<group>"; };
    607                 BEFC1DF30C07861A00B0BB3C /* upnp.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = upnp.h; path = libtransmission/upnp.h; sourceTree = "<group>"; };
    608                 BEFC1DF40C07861A00B0BB3C /* upnp.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = upnp.c; path = libtransmission/upnp.c; sourceTree = "<group>"; };
    609624                BEFC1DF50C07861A00B0BB3C /* transmission.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = transmission.h; path = libtransmission/transmission.h; sourceTree = "<group>"; };
    610625                BEFC1DF60C07861A00B0BB3C /* transmission.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = transmission.c; path = libtransmission/transmission.c; sourceTree = "<group>"; };
    611626                BEFC1DF70C07861A00B0BB3C /* tracker.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = tracker.h; path = libtransmission/tracker.h; sourceTree = "<group>"; };
     
    619634                BEFC1E030C07861A00B0BB3C /* platform.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = platform.c; path = libtransmission/platform.c; sourceTree = "<group>"; };
    620635                BEFC1E0C0C07861A00B0BB3C /* net.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = net.h; path = libtransmission/net.h; sourceTree = "<group>"; };
    621636                BEFC1E0D0C07861A00B0BB3C /* net.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = net.c; path = libtransmission/net.c; sourceTree = "<group>"; };
    622                 BEFC1E0E0C07861A00B0BB3C /* natpmp.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = natpmp.h; path = libtransmission/natpmp.h; sourceTree = "<group>"; };
    623                 BEFC1E0F0C07861A00B0BB3C /* natpmp.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = natpmp.c; path = libtransmission/natpmp.c; sourceTree = "<group>"; };
    624637                BEFC1E100C07861A00B0BB3C /* metainfo.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = metainfo.h; path = libtransmission/metainfo.h; sourceTree = "<group>"; };
    625638                BEFC1E110C07861A00B0BB3C /* metainfo.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = metainfo.c; path = libtransmission/metainfo.c; sourceTree = "<group>"; };
    626639                BEFC1E120C07861A00B0BB3C /* ipcparse.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ipcparse.h; path = libtransmission/ipcparse.h; sourceTree = "<group>"; };
     
    657670                        );
    658671                        runOnlyForDeploymentPostprocessing = 0;
    659672                };
     673                4DEFE4820CFC7269001D335E /* Frameworks */ = {
     674                        isa = PBXFrameworksBuildPhase;
     675                        buildActionMask = 2147483647;
     676                        files = (
     677                        );
     678                        runOnlyForDeploymentPostprocessing = 0;
     679                };
    660680                8D11072E0486CEB800E47090 /* Frameworks */ = {
    661681                        isa = PBXFrameworksBuildPhase;
    662682                        buildActionMask = 2147483647;
     
    690710                        files = (
    691711                                BE1183780CE161390002D0F3 /* libminiupnp.a in Frameworks */,
    692712                                BE75C38A0C72A1ED00DBEFE0 /* libevent.a in Frameworks */,
     713                                4DEFE5040CFC8BC5001D335E /* libpmpmyapp.a in Frameworks */,
    693714                        );
    694715                        runOnlyForDeploymentPostprocessing = 0;
    695716                };
     
    791812                                BEFC1D430C0783EE00B0BB3C /* transmission-proxy */,
    792813                                BE75C3490C729E9500DBEFE0 /* libevent.a */,
    793814                                BE1183480CE160960002D0F3 /* libminiupnp.a */,
     815                                4DEFE4840CFC7269001D335E /* libpmpmyapp.a */,
    794816                        );
    795817                        name = Products;
    796818                        sourceTree = "<group>";
     
    805827                                4DDBB71509E16B3F00284745 /* Libraries */,
    806828                                BE75C3570C72A0D600DBEFE0 /* libevent */,
    807829                                BE1183410CE15DF00002D0F3 /* libminiupnp */,
     830                                4DEFE47D0CFC7238001D335E /* pmpmyapp */,
    808831                                19C28FACFE9D520D11CA2CBB /* Products */,
    809832                        );
    810833                        name = Transmission;
     
    908931                4D1838DC09DEC04A0047D688 /* libtransmission */ = {
    909932                        isa = PBXGroup;
    910933                        children = (
     934                                4D36953E0CE8FD6800D781A9 /* nat.c */,
     935                                4D36953F0CE8FD6800D781A9 /* nat.h */,
    911936                                4D36BA600CA2F00800A63CA5 /* crypto.c */,
    912937                                4D36BA610CA2F00800A63CA5 /* crypto.h */,
    913938                                4D36BA630CA2F00800A63CA5 /* handshake.c */,
     
    935960                                BEFC1DF00C07861A00B0BB3C /* version.h */,
    936961                                BEFC1DF10C07861A00B0BB3C /* utils.h */,
    937962                                BEFC1DF20C07861A00B0BB3C /* utils.c */,
    938                                 BEFC1DF30C07861A00B0BB3C /* upnp.h */,
    939                                 BEFC1DF40C07861A00B0BB3C /* upnp.c */,
    940963                                BEFC1DF50C07861A00B0BB3C /* transmission.h */,
    941964                                BEFC1DF60C07861A00B0BB3C /* transmission.c */,
    942965                                BEFC1DF70C07861A00B0BB3C /* tracker.h */,
     
    950973                                BEFC1E030C07861A00B0BB3C /* platform.c */,
    951974                                BEFC1E0C0C07861A00B0BB3C /* net.h */,
    952975                                BEFC1E0D0C07861A00B0BB3C /* net.c */,
    953                                 BEFC1E0E0C07861A00B0BB3C /* natpmp.h */,
    954                                 BEFC1E0F0C07861A00B0BB3C /* natpmp.c */,
    955976                                BEFC1E100C07861A00B0BB3C /* metainfo.h */,
    956977                                BEFC1E110C07861A00B0BB3C /* metainfo.c */,
    957978                                BEFC1E120C07861A00B0BB3C /* ipcparse.h */,
     
    10021023                        name = CLI;
    10031024                        sourceTree = "<group>";
    10041025                };
     1026                4DEFE47D0CFC7238001D335E /* pmpmyapp */ = {
     1027                        isa = PBXGroup;
     1028                        children = (
     1029                                4DEFE4D20CFC821C001D335E /* route.c */,
     1030                                4DEFE4D30CFC821C001D335E /* route.h */,
     1031                                4DEFE4880CFC727A001D335E /* pmpmapper.c */,
     1032                                4DEFE4890CFC727A001D335E /* pmpmapper.h */,
     1033                        );
     1034                        name = pmpmyapp;
     1035                        path = "third-party/pmpmyapp";
     1036                        sourceTree = "<group>";
     1037                };
    10051038                A234D0D40C79FB6000A82373 /* Additions */ = {
    10061039                        isa = PBXGroup;
    10071040                        children = (
     
    11681201                        files = (
    11691202                                BEFC1E290C07861A00B0BB3C /* version.h in Headers */,
    11701203                                BEFC1E2A0C07861A00B0BB3C /* utils.h in Headers */,
    1171                                 BEFC1E2C0C07861A00B0BB3C /* upnp.h in Headers */,
    11721204                                BEFC1E2E0C07861A00B0BB3C /* transmission.h in Headers */,
    11731205                                BEFC1E300C07861A00B0BB3C /* tracker.h in Headers */,
    11741206                                BEFC1E350C07861A00B0BB3C /* shared.h in Headers */,
    11751207                                BEFC1E390C07861A00B0BB3C /* ratecontrol.h in Headers */,
    11761208                                BEFC1E3B0C07861A00B0BB3C /* platform.h in Headers */,
    11771209                                BEFC1E450C07861A00B0BB3C /* net.h in Headers */,
    1178                                 BEFC1E470C07861A00B0BB3C /* natpmp.h in Headers */,
    11791210                                BEFC1E490C07861A00B0BB3C /* metainfo.h in Headers */,
    11801211                                BEFC1E4B0C07861A00B0BB3C /* ipcparse.h in Headers */,
    11811212                                BEFC1E4D0C07861A00B0BB3C /* internal.h in Headers */,
     
    11981229                                4D36BA7A0CA2F00800A63CA5 /* peer-msgs.h in Headers */,
    11991230                                4D36BA7B0CA2F00800A63CA5 /* ptrarray.h in Headers */,
    12001231                                4D36BA7C0CA2F00800A63CA5 /* publish.h in Headers */,
     1232                                4D3695410CE8FD6800D781A9 /* nat.h in Headers */,
    12011233                                A25D2CBE0CF4C73E0096A262 /* stats.h in Headers */,
    12021234                        );
    12031235                        runOnlyForDeploymentPostprocessing = 0;
    12041236                };
     1237                4DEFE4800CFC7269001D335E /* Headers */ = {
     1238                        isa = PBXHeadersBuildPhase;
     1239                        buildActionMask = 2147483647;
     1240                        files = (
     1241                                4DEFE48B0CFC727A001D335E /* pmpmapper.h in Headers */,
     1242                                4DEFE4D50CFC821C001D335E /* route.h in Headers */,
     1243                        );
     1244                        runOnlyForDeploymentPostprocessing = 0;
     1245                };
    12051246                BE1183440CE160960002D0F3 /* Headers */ = {
    12061247                        isa = PBXHeadersBuildPhase;
    12071248                        buildActionMask = 2147483647;
     
    12441285                        dependencies = (
    12451286                                BE1183760CE161040002D0F3 /* PBXTargetDependency */,
    12461287                                BE75C34F0C729ED300DBEFE0 /* PBXTargetDependency */,
     1288                                4DEFE4900CFC7334001D335E /* PBXTargetDependency */,
    12471289                        );
    12481290                        name = libtransmission;
    12491291                        productName = transmission;
     
    12671309                        productReference = 4DDBB71909E16BAE00284745 /* transmissioncli */;
    12681310                        productType = "com.apple.product-type.tool";
    12691311                };
     1312                4DEFE4830CFC7269001D335E /* pmpmyapp */ = {
     1313                        isa = PBXNativeTarget;
     1314                        buildConfigurationList = 4DEFE48C0CFC727A001D335E /* Build configuration list for PBXNativeTarget "pmpmyapp" */;
     1315                        buildPhases = (
     1316                                4DEFE4800CFC7269001D335E /* Headers */,
     1317                                4DEFE4810CFC7269001D335E /* Sources */,
     1318                                4DEFE4820CFC7269001D335E /* Frameworks */,
     1319                        );
     1320                        buildRules = (
     1321                        );
     1322                        dependencies = (
     1323                        );
     1324                        name = pmpmyapp;
     1325                        productName = pmpmyapp;
     1326                        productReference = 4DEFE4840CFC7269001D335E /* libpmpmyapp.a */;
     1327                        productType = "com.apple.product-type.library.static";
     1328                };
    12701329                8D1107260486CEB800E47090 /* Transmission */ = {
    12711330                        isa = PBXNativeTarget;
    12721331                        buildConfigurationList = 4DF0C596089918A300DD8943 /* Build configuration list for PBXNativeTarget "Transmission" */;
     
    14101469                                BEFC1D340C0783EE00B0BB3C /* transmission-proxy */,
    14111470                                BE75C3480C729E9500DBEFE0 /* event */,
    14121471                                BE1183470CE160960002D0F3 /* miniupnp */,
     1472                                4DEFE4830CFC7269001D335E /* pmpmyapp */,
    14131473                        );
    14141474                };
    14151475/* End PBXProject section */
     
    15391599                        buildActionMask = 2147483647;
    15401600                        files = (
    15411601                                BEFC1E2B0C07861A00B0BB3C /* utils.c in Sources */,
    1542                                 BEFC1E2D0C07861A00B0BB3C /* upnp.c in Sources */,
    15431602                                BEFC1E2F0C07861A00B0BB3C /* transmission.c in Sources */,
    15441603                                BEFC1E310C07861A00B0BB3C /* tracker.c in Sources */,
    15451604                                BEFC1E320C07861A00B0BB3C /* torrent.c in Sources */,
     
    15471606                                BEFC1E3A0C07861A00B0BB3C /* ratecontrol.c in Sources */,
    15481607                                BEFC1E3C0C07861A00B0BB3C /* platform.c in Sources */,
    15491608                                BEFC1E460C07861A00B0BB3C /* net.c in Sources */,
    1550                                 BEFC1E480C07861A00B0BB3C /* natpmp.c in Sources */,
    15511609                                BEFC1E4A0C07861A00B0BB3C /* metainfo.c in Sources */,
    15521610                                BEFC1E4C0C07861A00B0BB3C /* ipcparse.c in Sources */,
    15531611                                BEFC1E4F0C07861A00B0BB3C /* inout.c in Sources */,
     
    15661624                                4D36BA740CA2F00800A63CA5 /* peer-io.c in Sources */,
    15671625                                4D36BA770CA2F00800A63CA5 /* peer-mgr.c in Sources */,
    15681626                                4D36BA790CA2F00800A63CA5 /* peer-msgs.c in Sources */,
     1627                                4D3695400CE8FD6800D781A9 /* nat.c in Sources */,
    15691628                                A25D2CBD0CF4C73E0096A262 /* stats.c in Sources */,
    15701629                        );
    15711630                        runOnlyForDeploymentPostprocessing = 0;
     
    15781637                        );
    15791638                        runOnlyForDeploymentPostprocessing = 0;
    15801639                };
     1640                4DEFE4810CFC7269001D335E /* Sources */ = {
     1641                        isa = PBXSourcesBuildPhase;
     1642                        buildActionMask = 2147483647;
     1643                        files = (
     1644                                4DEFE48A0CFC727A001D335E /* pmpmapper.c in Sources */,
     1645                                4DEFE4D40CFC821C001D335E /* route.c in Sources */,
     1646                        );
     1647                        runOnlyForDeploymentPostprocessing = 0;
     1648                };
    15811649                8D11072C0486CEB800E47090 /* Sources */ = {
    15821650                        isa = PBXSourcesBuildPhase;
    15831651                        buildActionMask = 2147483647;
     
    17111779                        target = 4D18389609DEC0030047D688 /* libtransmission */;
    17121780                        targetProxy = 4D9A2BF409E16D30002D0FF9 /* PBXContainerItemProxy */;
    17131781                };
     1782                4DEFE4900CFC7334001D335E /* PBXTargetDependency */ = {
     1783                        isa = PBXTargetDependency;
     1784                        target = 4DEFE4830CFC7269001D335E /* pmpmyapp */;
     1785                        targetProxy = 4DEFE48F0CFC7334001D335E /* PBXContainerItemProxy */;
     1786                };
    17141787                BE1183760CE161040002D0F3 /* PBXTargetDependency */ = {
    17151788                        isa = PBXTargetDependency;
    17161789                        target = BE1183470CE160960002D0F3 /* miniupnp */;
     
    18541927                        isa = XCBuildConfiguration;
    18551928                        buildSettings = {
    18561929                                HEADER_SEARCH_PATHS = (
     1930                                        "third-party/pmpmyapp",
    18571931                                        "third-party/libevent",
    18581932                                        "third-party",
    18591933                                );
     1934                                LIBRARY_SEARCH_PATHS = (
     1935                                        "$(inherited)",
     1936                                        "\"$(SRCROOT)/build/Development\"",
     1937                                );
    18601938                                OTHER_CFLAGS = (
    18611939                                        "-DSYS_DARWIN",
    18621940                                        "-DHAVE_OPENSSL",
     
    19492027                        isa = XCBuildConfiguration;
    19502028                        buildSettings = {
    19512029                                HEADER_SEARCH_PATHS = (
     2030                                        "third-party/pmpmyapp",
    19522031                                        "third-party/libevent",
    19532032                                        "third-party",
    19542033                                );
     2034                                LIBRARY_SEARCH_PATHS = (
     2035                                        "$(inherited)",
     2036                                        "\"$(SRCROOT)/build/Development\"",
     2037                                );
    19552038                                OTHER_CFLAGS = (
    19562039                                        "-DSYS_DARWIN",
    19572040                                        "-DHAVE_OPENSSL",
     
    19732056                        };
    19742057                        name = Release;
    19752058                };
     2059                4DEFE4850CFC7269001D335E /* Release */ = {
     2060                        isa = XCBuildConfiguration;
     2061                        buildSettings = {
     2062                                COPY_PHASE_STRIP = YES;
     2063                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
     2064                                GCC_ENABLE_FIX_AND_CONTINUE = NO;
     2065                                GCC_MODEL_TUNING = G5;
     2066                                INSTALL_PATH = /usr/local/lib;
     2067                                PREBINDING = NO;
     2068                                PRODUCT_NAME = pmpmyapp;
     2069                                ZERO_LINK = NO;
     2070                        };
     2071                        name = Release;
     2072                };
     2073                4DEFE4860CFC7269001D335E /* Release - Debug */ = {
     2074                        isa = XCBuildConfiguration;
     2075                        buildSettings = {
     2076                                GCC_ENABLE_FIX_AND_CONTINUE = YES;
     2077                                GCC_MODEL_TUNING = G5;
     2078                                INSTALL_PATH = /usr/local/lib;
     2079                                PREBINDING = NO;
     2080                                PRODUCT_NAME = pmpmyapp;
     2081                                ZERO_LINK = YES;
     2082                        };
     2083                        name = "Release - Debug";
     2084                };
     2085                4DEFE4870CFC7269001D335E /* Development */ = {
     2086                        isa = XCBuildConfiguration;
     2087                        buildSettings = {
     2088                                COPY_PHASE_STRIP = NO;
     2089                                GCC_DYNAMIC_NO_PIC = NO;
     2090                                GCC_ENABLE_FIX_AND_CONTINUE = YES;
     2091                                GCC_MODEL_TUNING = G5;
     2092                                GCC_OPTIMIZATION_LEVEL = 0;
     2093                                INSTALL_PATH = /usr/local/lib;
     2094                                PREBINDING = NO;
     2095                                PRODUCT_NAME = pmpmyapp;
     2096                                ZERO_LINK = YES;
     2097                        };
     2098                        name = Development;
     2099                };
    19762100                4DF0C599089918A300DD8943 /* Release */ = {
    19772101                        isa = XCBuildConfiguration;
    19782102                        buildSettings = {
     
    20412165                        isa = XCBuildConfiguration;
    20422166                        buildSettings = {
    20432167                                HEADER_SEARCH_PATHS = (
     2168                                        "third-party/pmpmyapp",
    20442169                                        "third-party/libevent",
    20452170                                        "third-party",
    20462171                                );
     2172                                LIBRARY_SEARCH_PATHS = (
     2173                                        "$(inherited)",
     2174                                        "\"$(SRCROOT)/build/Development\"",
     2175                                );
    20472176                                OTHER_CFLAGS = (
    20482177                                        "-DSYS_DARWIN",
    20492178                                        "-DHAVE_OPENSSL",
     
    21062235                        isa = XCBuildConfiguration;
    21072236                        buildSettings = {
    21082237                                COPY_PHASE_STRIP = YES;
    2109                                 DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
    2110                                 GCC_ENABLE_FIX_AND_CONTINUE = NO;
    2111                                 GCC_MODEL_TUNING = G5;
    21122238                                INSTALL_PATH = /usr/local/lib;
    21132239                                OTHER_CFLAGS = (
    21142240                                        "$(inherited)",
    21152241                                        "-DNDEBUG",
    21162242                                );
    21172243                                OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)";
    2118                                 PREBINDING = NO;
    21192244                                PRODUCT_NAME = miniupnp;
    2120                                 ZERO_LINK = NO;
    21212245                        };
    21222246                        name = Release;
    21232247                };
    21242248                BE11834A0CE160960002D0F3 /* Release - Debug */ = {
    21252249                        isa = XCBuildConfiguration;
    21262250                        buildSettings = {
    2127                                 GCC_ENABLE_FIX_AND_CONTINUE = YES;
    2128                                 GCC_MODEL_TUNING = G5;
    21292251                                INSTALL_PATH = /usr/local/lib;
    21302252                                OTHER_CFLAGS = (
    21312253                                        "$(inherited)",
    21322254                                        "-DNDEBUG",
    21332255                                );
    21342256                                OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)";
    2135                                 PREBINDING = NO;
    21362257                                PRODUCT_NAME = miniupnp;
    2137                                 ZERO_LINK = YES;
    21382258                        };
    21392259                        name = "Release - Debug";
    21402260                };
     
    21422262                        isa = XCBuildConfiguration;
    21432263                        buildSettings = {
    21442264                                COPY_PHASE_STRIP = NO;
    2145                                 GCC_DYNAMIC_NO_PIC = NO;
    2146                                 GCC_ENABLE_FIX_AND_CONTINUE = YES;
    2147                                 GCC_MODEL_TUNING = G5;
    2148                                 GCC_OPTIMIZATION_LEVEL = 0;
    21492265                                INSTALL_PATH = /usr/local/lib;
    21502266                                OTHER_CFLAGS = (
    21512267                                        "$(inherited)",
    21522268                                        "-DNDEBUG",
    21532269                                );
    21542270                                OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)";
    2155                                 PREBINDING = NO;
    21562271                                PRODUCT_NAME = miniupnp;
    2157                                 ZERO_LINK = YES;
    21582272                        };
    21592273                        name = Development;
    21602274                };
     
    22262340                        defaultConfigurationIsVisible = 0;
    22272341                        defaultConfigurationName = Development;
    22282342                };
     2343                4DEFE48C0CFC727A001D335E /* Build configuration list for PBXNativeTarget "pmpmyapp" */ = {
     2344                        isa = XCConfigurationList;
     2345                        buildConfigurations = (
     2346                                4DEFE4850CFC7269001D335E /* Release */,
     2347                                4DEFE4860CFC7269001D335E /* Release - Debug */,
     2348                                4DEFE4870CFC7269001D335E /* Development */,
     2349                        );
     2350                        defaultConfigurationIsVisible = 0;
     2351                        defaultConfigurationName = Development;
     2352                };
    22292353                4DF0C596089918A300DD8943 /* Build configuration list for PBXNativeTarget "Transmission" */ = {
    22302354                        isa = XCConfigurationList;
    22312355                        buildConfigurations = (
  • third-party/miniupnp/upnpcommands.c

     
    292292        /*puts(buffer);*/
    293293        ParseNameValue(buffer, bufsize, &pdata);
    294294        resVal = GetValueFromNameValueList(&pdata, "errorCode");
    295         ret = resVal?0:1;
    296295        /* Do something with resVal if not null ! */
    297296        /*printf("AddPortMapping errorCode = '%s'\n", resVal); */
    298297        ClearNameValueList(&pdata);
    299298        free(AddPortMappingArgs);
    300         return ret;
     299    return resVal;
    301300}
    302301
    303 void UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
    304                             const char * extPort, const char * proto)
     302int
     303UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
     304                       const char * extPort, const char * proto)
    305305{
    306306        /*struct NameValueParserData pdata;*/
    307307        struct UPNParg * DeletePortMappingArgs;
    308308        char buffer[4096];
    309309        int bufsize = 4096;
     310    int err = 0;
     311        struct NameValueParserData pdata;
     312    const char * resVal;
    310313
    311314        if(!extPort)
    312315                return;
     
    318321        DeletePortMappingArgs[2].elt = "NewProtocol";
    319322        DeletePortMappingArgs[2].val = proto;
    320323        simpleUPnPcommand(-1, controlURL, servicetype,
    321                           "DeletePortMapping",
    322                                           DeletePortMappingArgs, buffer, &bufsize);
     324                      "DeletePortMapping",
     325                      DeletePortMappingArgs, buffer, &bufsize);
     326   
     327        ParseNameValue(buffer, bufsize, &pdata);
     328        resVal = GetValueFromNameValueList(&pdata, "errorCode");
     329   
    323330        /*DisplayNameValueList(buffer, bufsize);*/
    324331        free(DeletePortMappingArgs);
     332    return resVal;
    325333}
    326334
    327335int UPNP_GetGenericPortMappingEntry(const char * controlURL,
  • third-party/miniupnp/upnpcommands.h

     
    5555                                                        unsigned int * bitrateDown,
    5656                                                        unsigned int * bitrateUp);
    5757
    58 /* Returns zero if unable to add the port mapping, otherwise non-zero
    59  * to indicate success */
     58/* Returns zero in case of success, otherwise a non-zero error code compatible
     59 * with UPnP specification */
    6060LIBSPEC int
    6161UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
    6262                    const char * extPort,
     
    6464                                        const char * inClient,
    6565                                        const char * desc,
    6666                    const char * proto);
    67 
    68 LIBSPEC void
     67   
     68/* Returns zero in case of success, otherwise a non-zero error code compatible
     69 * with UPnP specification */
     70LIBSPEC int
    6971UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
    7072                       const char * extPort, const char * proto);
    7173