source: trunk/libtransmission/shared.c @ 4102

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

finish the `shared' update: bind & listen the incoming port.
better logging in network code.

  • Property svn:keywords set to Date Rev Author Id
File size: 5.6 KB
Line 
1/******************************************************************************
2 * $Id: shared.c 4102 2007-12-09 00:28:34Z charles $
3 *
4 * Copyright (c) 2005-2007 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 <string.h>
26#include <stdio.h>
27
28#include <sys/types.h>
29
30#include "transmission.h"
31#include "natpmp.h"
32#include "net.h"
33#include "peer-mgr.h"
34#include "shared.h"
35#include "trevent.h"
36#include "upnp.h"
37#include "utils.h"
38
39struct tr_shared
40{
41    tr_handle * h;
42    tr_timer  * pulseTimer;
43
44    /* Incoming connections */
45    int bindPort;
46    int bindSocket;
47
48    /* port forwarding */
49    int isEnabled;
50    int publicPort;
51    tr_nat_traversal_status natStatus;
52    tr_upnp * upnp;
53    tr_natpmp  * natpmp;
54
55    int isShuttingDown;
56};
57
58#define NATKEY "Port Mapping: "
59
60/***
61****
62***/
63
64static const char*
65getNatStateStr( int state )
66{
67    switch( state )
68    {
69        case TR_NAT_TRAVERSAL_MAPPING:   return "mapping";
70        case TR_NAT_TRAVERSAL_MAPPED:    return "mapped";
71        case TR_NAT_TRAVERSAL_UNMAPPING: return "unmapping";
72        case TR_NAT_TRAVERSAL_UNMAPPED:  return "unmapped";
73        case TR_NAT_TRAVERSAL_ERROR:     return "error";
74    }
75
76    return "notfound";
77}
78
79static void
80natPulse( tr_shared * s )
81{
82    tr_nat_traversal_status status;
83    const int port = s->publicPort;
84    const int isEnabled = s->isEnabled && !s->isShuttingDown;
85
86    status = tr_natpmpPulse( s->natpmp, port, isEnabled );
87    if( status == TR_NAT_TRAVERSAL_ERROR )
88        status = tr_upnpPulse( s->upnp, port, isEnabled );
89    if( status != s->natStatus ) {
90        tr_inf( NATKEY "mapping state changed from '%s' to '%s'", getNatStateStr(s->natStatus), getNatStateStr(status) );
91        s->natStatus = status;
92    }
93}
94
95static void
96incomingPeersPulse( tr_shared * s )
97{
98    if( s->bindSocket >= 0 && ( s->bindPort != s->publicPort ) )
99    {
100        tr_inf( NATKEY "closing port %d", s->bindPort );
101        tr_netClose( s->bindSocket );
102        s->bindSocket = -1;
103    }
104
105    if( s->bindPort != s->publicPort )
106    {
107        int socket;
108        errno = 0;
109        socket = tr_netBindTCP( s->publicPort );
110        if( socket >= 0 ) {
111            tr_inf( NATKEY "opened port %d to listen for incoming peer connections", s->publicPort );
112            s->bindPort = s->publicPort;
113            s->bindSocket = socket;
114            listen( s->bindSocket, 5 );
115        } else {
116            tr_err( NATKEY "unable to open port %d to listen for incoming peer connections (errno is %d - %s)",
117                    s->publicPort, errno, strerror(errno) );
118            s->bindPort = -1;
119            s->bindSocket = -1;
120        }
121    }
122   
123    for( ;; ) /* check for new incoming peer connections */   
124    {
125        int socket;
126        uint16_t port;
127        struct in_addr addr;
128
129        if( s->bindSocket < 0 )
130            break;
131
132        socket = tr_netAccept( s->bindSocket, &addr, &port );
133        if( socket < 0 )
134            break;
135
136        tr_peerMgrAddIncoming( s->h->peerMgr, &addr, port, socket );
137    }
138}
139
140static int
141sharedPulse( void * vshared )
142{
143    int keepPulsing = 1;
144    tr_shared * shared = vshared;
145
146    natPulse( shared );
147
148    if( !shared->isShuttingDown )
149    {
150        incomingPeersPulse( shared );
151    }
152    else if( ( shared->natStatus == TR_NAT_TRAVERSAL_ERROR ) || ( shared->natStatus == TR_NAT_TRAVERSAL_UNMAPPED ) )
153    {
154        tr_dbg( NATKEY "port mapping shut down" );
155        shared->h->shared = NULL;
156        tr_netClose( shared->bindSocket );
157        tr_natpmpClose( shared->natpmp );
158        tr_upnpClose( shared->upnp );
159        tr_free( shared );
160        keepPulsing = 0;
161    }
162
163    return keepPulsing;
164}
165
166/***
167****
168***/
169
170tr_shared *
171tr_sharedInit( tr_handle * h )
172{
173    tr_shared * s = tr_new0( tr_shared, 1 );
174
175    s->h            = h;
176    s->publicPort   = -1;
177    s->bindPort     = -1;
178    s->bindSocket   = -1;
179    s->natpmp       = tr_natpmpInit();
180    s->upnp         = tr_upnpInit();
181    s->pulseTimer   = tr_timerNew( h, sharedPulse, s, 500 );
182    s->isEnabled    = 0;
183    s->natStatus    = TR_NAT_TRAVERSAL_UNMAPPED;
184
185    return s;
186}
187
188void
189tr_sharedShuttingDown( tr_shared * s )
190{
191    s->isShuttingDown = 1;
192}
193
194void
195tr_sharedSetPort( tr_shared * s, int port )
196{
197    tr_torrent * tor;
198
199    s->publicPort = port;
200
201    for( tor = s->h->torrentList; tor; tor = tor->next )
202        tr_torrentChangeMyPort( tor );
203}
204
205int
206tr_sharedGetPublicPort( const tr_shared * s )
207{
208    return s->publicPort;
209}
210
211void
212tr_sharedTraversalEnable( tr_shared * s, int isEnabled )
213{
214    s->isEnabled = isEnabled;
215}
216
217int
218tr_sharedTraversalStatus( const tr_shared * s )
219{
220    return s->natStatus;
221}
Note: See TracBrowser for help on using the repository browser.