source: trunk/libtransmission/upnp.c @ 4142

Last change on this file since 4142 was 4142, checked in by charles, 15 years ago

add extra debugging messages for upnpDiscover()

  • Property svn:keywords set to Date Rev Author Id
File size: 4.9 KB
Line 
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: upnp.c 4142 2007-12-13 02:48:30Z charles $
11 */
12
13#include <assert.h>
14#include <errno.h>
15#include <stdio.h> /* snprintf */
16#include <string.h> /* strerror */
17
18#include <miniupnp/miniwget.h>
19#include <miniupnp/miniupnpc.h>
20#include <miniupnp/upnpcommands.h>
21
22#include "transmission.h"
23#include "internal.h"
24#include "shared.h"
25#include "utils.h"
26#include "upnp.h"
27
28#define KEY "Port Mapping (UPNP): "
29
30typedef enum
31{
32    TR_UPNP_IDLE,
33    TR_UPNP_ERR,
34    TR_UPNP_DISCOVER,
35    TR_UPNP_MAP,
36    TR_UPNP_UNMAP
37}
38tr_upnp_state;
39
40struct tr_upnp
41{
42    struct UPNPUrls urls;
43    struct IGDdatas data;
44    int port;
45    char lanaddr[16];
46    unsigned int isMapped;
47    unsigned int hasDiscovered : 1;
48    tr_upnp_state state;
49};
50
51/**
52***
53**/
54
55tr_upnp*
56tr_upnpInit( void )
57{
58    tr_upnp * ret = tr_new0( tr_upnp, 1 );
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 ) || ( handle->state == TR_UPNP_ERR ) );
68
69    if( handle->hasDiscovered )
70        FreeUPNPUrls( &handle->urls );
71    tr_free( handle );
72}
73
74/**
75***
76**/
77
78int
79tr_upnpPulse( tr_upnp * handle, int port, int isEnabled )
80{
81    int ret;
82
83    if( handle->state == TR_UPNP_IDLE )
84    {
85        if( !handle->hasDiscovered )
86            handle->state = TR_UPNP_DISCOVER;
87    }
88
89    if( handle->state == TR_UPNP_DISCOVER )
90    {
91        struct UPNPDev * devlist;
92        errno = 0;
93        devlist = upnpDiscover( 2000, NULL );
94        if( devlist == NULL ) {
95            tr_err( KEY "upnpDiscover returned NULL (errno %d - %s)", errno, strerror(errno) );
96        }
97        errno = 0;
98        if( UPNP_GetValidIGD( devlist, &handle->urls, &handle->data, handle->lanaddr, sizeof(handle->lanaddr))) {
99            tr_inf( KEY "found Internet Gateway Device '%s'", handle->urls.controlURL );
100            tr_inf( KEY "local LAN IP Address is '%s'", handle->lanaddr );
101            handle->state = TR_UPNP_IDLE;
102            handle->hasDiscovered = 1;
103        } else {
104            handle->state = TR_UPNP_ERR;
105            tr_err( KEY "UPNP_GetValidIGD failed.  (errno %d - %s)", errno, strerror(errno) );
106        }
107        freeUPNPDevlist( devlist );
108    }
109
110    if( handle->state == TR_UPNP_IDLE )
111    {
112        if( handle->isMapped && ( !isEnabled || ( handle->port != port ) ) )
113            handle->state = TR_UPNP_UNMAP;
114    }
115
116    if( handle->state == TR_UPNP_UNMAP )
117    {
118        char portStr[16];
119        snprintf( portStr, sizeof(portStr), "%d", handle->port );
120        UPNP_DeletePortMapping( handle->urls.controlURL,
121                                handle->data.servicetype,
122                                portStr, "TCP" );
123        tr_dbg( KEY "stopping port forwarding of '%s', service '%s'",
124                handle->urls.controlURL, handle->data.servicetype );
125        handle->isMapped = 0;
126        handle->state = TR_UPNP_IDLE;
127        handle->port = -1;
128    }
129
130    if( handle->state == TR_UPNP_IDLE )
131    {
132        if( isEnabled && !handle->isMapped )
133            handle->state = TR_UPNP_MAP;
134    }
135
136    if( handle->state == TR_UPNP_MAP )
137    {
138        char portStr[16];
139        snprintf( portStr, sizeof(portStr), "%d", port );
140        errno = 0;
141        handle->isMapped = ( handle->urls.controlURL != NULL ) && 
142                           ( handle->data.servicetype != NULL ) &&
143                           ( UPNP_AddPortMapping( handle->urls.controlURL,
144                                                  handle->data.servicetype,
145                                                  portStr, portStr, handle->lanaddr,
146                                                  "Transmission", "TCP" ) );
147        tr_inf( KEY "port forwarding via '%s', service '%s'.  (local address: %s:%d)",
148                handle->urls.controlURL, handle->data.servicetype, handle->lanaddr, handle->port );
149        if( handle->isMapped ) {
150            tr_inf( KEY "port forwarding successful!" );
151            handle->port = port;
152            handle->state = TR_UPNP_IDLE;
153        } else {
154            tr_err( KEY "port forwarding failed (errno %d - %s)", errno, strerror(errno) );
155            handle->port = -1;
156            handle->state = TR_UPNP_ERR;
157        }
158    }
159
160    if( handle->state == TR_UPNP_ERR )
161        ret = TR_NAT_TRAVERSAL_ERROR;
162    else if( ( handle->state == TR_UPNP_IDLE ) && handle->isMapped )
163        ret = TR_NAT_TRAVERSAL_MAPPED;
164    else if( ( handle->state == TR_UPNP_IDLE ) && !handle->isMapped )
165        ret = TR_NAT_TRAVERSAL_UNMAPPED;
166    else if( handle->state == TR_UPNP_MAP )
167        ret = TR_NAT_TRAVERSAL_MAPPING;
168    else if( handle->state == TR_UPNP_UNMAP )
169        ret = TR_NAT_TRAVERSAL_UNMAPPING;
170    return ret;
171}
Note: See TracBrowser for help on using the repository browser.