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
Line 
1/*
2 * This file Copyright (C) 2007-2009 Charles Kerr <charles@transmissionbt.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: upnp.c 7658 2009-01-10 23:09:07Z charles $
11 */
12
13#include <assert.h>
14#include <errno.h>
15
16#include <miniupnp/miniupnpc.h>
17#include <miniupnp/upnpcommands.h>
18
19#include "transmission.h"
20#include "port-forwarding.h"
21#include "session.h"
22#include "utils.h"
23#include "upnp.h"
24
25static const char *
26getKey( void ) { return _( "Port Forwarding (UPnP)" ); }
27
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
38struct tr_upnp
39{
40    tr_bool            hasDiscovered;
41    struct UPNPUrls    urls;
42    struct IGDdatas    data;
43    int                port;
44    char               lanaddr[16];
45    unsigned int       isMapped;
46    tr_upnp_state      state;
47};
48
49/**
50***
51**/
52
53tr_upnp*
54tr_upnpInit( void )
55{
56    tr_upnp * ret = tr_new0( tr_upnp, 1 );
57
58    ret->state = TR_UPNP_DISCOVER;
59    ret->port = -1;
60    return ret;
61}
62
63void
64tr_upnpClose( tr_upnp * handle )
65{
66    assert( !handle->isMapped );
67    assert( ( handle->state == TR_UPNP_IDLE )
68          || ( handle->state == TR_UPNP_ERR )
69          || ( handle->state == TR_UPNP_DISCOVER ) );
70
71    if( handle->hasDiscovered )
72        FreeUPNPUrls( &handle->urls );
73    tr_free( handle );
74}
75
76/**
77***
78**/
79
80int
81tr_upnpPulse( tr_upnp * handle,
82              int       port,
83              int       isEnabled )
84{
85    int ret;
86
87    if( isEnabled && ( handle->state == TR_UPNP_DISCOVER ) )
88    {
89        struct UPNPDev * devlist;
90        errno = 0;
91        devlist = upnpDiscover( 2000, NULL, NULL, 0 );
92        if( devlist == NULL )
93        {
94            tr_ndbg(
95                 getKey( ), "upnpDiscover failed (errno %d - %s)", errno,
96                tr_strerror( errno ) );
97        }
98        errno = 0;
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 );
107            handle->state = TR_UPNP_IDLE;
108            handle->hasDiscovered = 1;
109        }
110        else
111        {
112            handle->state = TR_UPNP_ERR;
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!" );
120        }
121        freeUPNPDevlist( devlist );
122    }
123
124    if( handle->state == TR_UPNP_IDLE )
125    {
126        if( handle->isMapped && ( !isEnabled || ( handle->port != port ) ) )
127            handle->state = TR_UPNP_UNMAP;
128    }
129
130    if( handle->state == TR_UPNP_UNMAP )
131    {
132        char portStr[16];
133        tr_snprintf( portStr, sizeof( portStr ), "%d", handle->port );
134        UPNP_DeletePortMapping( handle->urls.controlURL,
135                                handle->data.servicetype,
136                                portStr, "TCP" );
137        tr_ninf( getKey( ),
138                 _(
139                     "Stopping port forwarding through \"%s\", service \"%s\"" ),
140                 handle->urls.controlURL, handle->data.servicetype );
141        handle->isMapped = 0;
142        handle->state = TR_UPNP_IDLE;
143        handle->port = -1;
144    }
145
146    if( handle->state == TR_UPNP_IDLE )
147    {
148        if( isEnabled && !handle->isMapped )
149            handle->state = TR_UPNP_MAP;
150    }
151
152    if( handle->state == TR_UPNP_MAP )
153    {
154        int  err = -1;
155        errno = 0;
156
157        if( !handle->urls.controlURL || !handle->data.servicetype )
158            handle->isMapped = 0;
159        else
160        {
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 );
165            err = UPNP_AddPortMapping( handle->urls.controlURL,
166                                       handle->data.servicetype,
167                                       portStr, portStr, handle->lanaddr,
168                                       desc, "TCP" );
169            handle->isMapped = !err;
170        }
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!" ) );
179            handle->port = port;
180            handle->state = TR_UPNP_IDLE;
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!" );
191            handle->port = -1;
192            handle->state = TR_UPNP_ERR;
193        }
194    }
195
196    switch( handle->state )
197    {
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;
213    }
214
215    return ret;
216}
217
Note: See TracBrowser for help on using the repository browser.