source: trunk/libtransmission/upnp.c @ 7658

Last change on this file since 7658 was 7658, checked in by charles, 13 years ago

(trunk) update the GPL code's copyright dates

  • Property svn:keywords set to Date Rev Author Id
File size: 5.8 KB
RevLine 
[3731]1/*
[7658]2 * This file Copyright (C) 2007-2009 Charles Kerr <charles@transmissionbt.com>
[864]3 *
[3731]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)
[6795]6 * so that the bulk of its code can remain under the MIT license.
[3731]7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
[864]9 *
[3743]10 * $Id: upnp.c 7658 2009-01-10 23:09:07Z charles $
[3731]11 */
[864]12
[4092]13#include <assert.h>
[4112]14#include <errno.h>
[2544]15
[3731]16#include <miniupnp/miniupnpc.h>
17#include <miniupnp/upnpcommands.h>
[2619]18
[864]19#include "transmission.h"
[5585]20#include "port-forwarding.h"
21#include "session.h"
[3731]22#include "utils.h"
[2311]23#include "upnp.h"
[864]24
[6795]25static const char *
26getKey( void ) { return _( "Port Forwarding (UPnP)" ); }
[5209]27
[4092]28typedef enum
29{
30    TR_UPNP_IDLE,
31    TR_UPNP_ERR,
32    TR_UPNP_DISCOVER,
33    TR_UPNP_MAP,
34    TR_UPNP_UNMAP
35}
36tr_upnp_state;
37
[3731]38struct tr_upnp
[864]39{
[7173]40    tr_bool            hasDiscovered;
[6795]41    struct UPNPUrls    urls;
42    struct IGDdatas    data;
43    int                port;
44    char               lanaddr[16];
45    unsigned int       isMapped;
46    tr_upnp_state      state;
[2898]47};
[864]48
[3731]49/**
50***
51**/
[864]52
[3731]53tr_upnp*
[2898]54tr_upnpInit( void )
[864]55{
[3731]56    tr_upnp * ret = tr_new0( tr_upnp, 1 );
[6795]57
[4154]58    ret->state = TR_UPNP_DISCOVER;
[3731]59    ret->port = -1;
[864]60    return ret;
61}
62
63void
[3731]64tr_upnpClose( tr_upnp * handle )
[864]65{
[4092]66    assert( !handle->isMapped );
[4157]67    assert( ( handle->state == TR_UPNP_IDLE )
[6795]68          || ( handle->state == TR_UPNP_ERR )
69          || ( handle->state == TR_UPNP_DISCOVER ) );
[4092]70
[3770]71    if( handle->hasDiscovered )
72        FreeUPNPUrls( &handle->urls );
[3731]73    tr_free( handle );
[864]74}
75
[3731]76/**
77***
78**/
[1720]79
[4092]80int
[6795]81tr_upnpPulse( tr_upnp * handle,
82              int       port,
83              int       isEnabled )
[864]84{
[4092]85    int ret;
86
[4154]87    if( isEnabled && ( handle->state == TR_UPNP_DISCOVER ) )
[3770]88    {
[4142]89        struct UPNPDev * devlist;
[4112]90        errno = 0;
[6849]91        devlist = upnpDiscover( 2000, NULL, NULL, 0 );
[6795]92        if( devlist == NULL )
93        {
94            tr_ndbg(
95                 getKey( ), "upnpDiscover failed (errno %d - %s)", errno,
96                tr_strerror( errno ) );
[4142]97        }
98        errno = 0;
[6795]99        if( UPNP_GetValidIGD( devlist, &handle->urls, &handle->data,
100                             handle->lanaddr, sizeof( handle->lanaddr ) ) )
101        {
102            tr_ninf( getKey( ), _(
103                         "Found Internet Gateway Device \"%s\"" ),
104                     handle->urls.controlURL );
105            tr_ninf( getKey( ), _(
106                         "Local Address is \"%s\"" ), handle->lanaddr );
[4092]107            handle->state = TR_UPNP_IDLE;
108            handle->hasDiscovered = 1;
[6795]109        }
110        else
111        {
[4092]112            handle->state = TR_UPNP_ERR;
[6795]113            tr_ndbg(
114                 getKey( ), "UPNP_GetValidIGD failed (errno %d - %s)",
115                errno,
116                tr_strerror( errno ) );
117            tr_ndbg(
118                getKey( ),
119                "If your router supports UPnP, please make sure UPnP is enabled!" );
[3770]120        }
121        freeUPNPDevlist( devlist );
122    }
123
[4092]124    if( handle->state == TR_UPNP_IDLE )
[864]125    {
[4092]126        if( handle->isMapped && ( !isEnabled || ( handle->port != port ) ) )
127            handle->state = TR_UPNP_UNMAP;
[2034]128    }
[864]129
[4092]130    if( handle->state == TR_UPNP_UNMAP )
[864]131    {
[3731]132        char portStr[16];
[6795]133        tr_snprintf( portStr, sizeof( portStr ), "%d", handle->port );
[3731]134        UPNP_DeletePortMapping( handle->urls.controlURL,
135                                handle->data.servicetype,
136                                portStr, "TCP" );
[6795]137        tr_ninf( getKey( ),
138                 _(
139                     "Stopping port forwarding through \"%s\", service \"%s\"" ),
140                 handle->urls.controlURL, handle->data.servicetype );
[4092]141        handle->isMapped = 0;
142        handle->state = TR_UPNP_IDLE;
143        handle->port = -1;
144    }
[864]145
[4092]146    if( handle->state == TR_UPNP_IDLE )
147    {
148        if( isEnabled && !handle->isMapped )
149            handle->state = TR_UPNP_MAP;
[864]150    }
151
[4092]152    if( handle->state == TR_UPNP_MAP )
153    {
[6795]154        int  err = -1;
[4112]155        errno = 0;
[4311]156
157        if( !handle->urls.controlURL || !handle->data.servicetype )
158            handle->isMapped = 0;
[6795]159        else
160        {
[7342]161            char portStr[16];
162            char desc[64];
163            tr_snprintf( portStr, sizeof( portStr ), "%d", port );
164            tr_snprintf( desc, sizeof( desc ), "%s at %d", TR_NAME, port );
[4311]165            err = UPNP_AddPortMapping( handle->urls.controlURL,
166                                       handle->data.servicetype,
167                                       portStr, portStr, handle->lanaddr,
[7342]168                                       desc, "TCP" );
[4311]169            handle->isMapped = !err;
170        }
[6795]171        tr_ninf( getKey( ),
172                 _(
173                     "Port forwarding through \"%s\", service \"%s\".  (local address: %s:%d)" ),
174                 handle->urls.controlURL, handle->data.servicetype,
175                 handle->lanaddr, port );
176        if( handle->isMapped )
177        {
178            tr_ninf( getKey( ), _( "Port forwarding successful!" ) );
[4092]179            handle->port = port;
180            handle->state = TR_UPNP_IDLE;
[6795]181        }
182        else
183        {
184            tr_ndbg(
185                 getKey( ),
186                "Port forwarding failed with error %d (errno %d - %s)", err,
187                errno, tr_strerror( errno ) );
188            tr_ndbg(
189                getKey( ),
190                "If your router supports UPnP, please make sure UPnP is enabled!" );
[4092]191            handle->port = -1;
192            handle->state = TR_UPNP_ERR;
193        }
194    }
[864]195
[4154]196    switch( handle->state )
197    {
[6795]198        case TR_UPNP_DISCOVER:
199            ret = TR_PORT_UNMAPPED; break;
200
201        case TR_UPNP_MAP:
202            ret = TR_PORT_MAPPING; break;
203
204        case TR_UPNP_UNMAP:
205            ret = TR_PORT_UNMAPPING; break;
206
207        case TR_UPNP_IDLE:
208            ret = handle->isMapped ? TR_PORT_MAPPED
209                  : TR_PORT_UNMAPPED; break;
210
211        default:
212            ret = TR_PORT_ERROR; break;
[4154]213    }
214
[4092]215    return ret;
[864]216}
[6795]217
Note: See TracBrowser for help on using the repository browser.