source: trunk/libtransmission/net.c @ 7448

Last change on this file since 7448 was 7448, checked in by jhujhiti, 13 years ago

add some debugging stuff to track down where some bogus addresses are coming from

  • Property svn:keywords set to Date Rev Author Id
File size: 13.0 KB
Line 
1/******************************************************************************
2 * $Id: net.c 7448 2008-12-21 19:13:52Z jhujhiti $
3 *
4 * Copyright (c) 2005-2008 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 <errno.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <assert.h>
30
31#include <sys/types.h>
32
33#ifdef WIN32
34 #include <winsock2.h> /* inet_addr */
35#else
36 #include <arpa/inet.h> /* inet_addr */
37 #include <netdb.h>
38 #include <fcntl.h>
39#endif
40
41#include <evutil.h>
42
43#include "transmission.h"
44#include "fdlimit.h"
45#include "natpmp.h"
46#include "net.h"
47#include "peer-io.h"
48#include "platform.h"
49#include "utils.h"
50
51const tr_address tr_in6addr_any = { TR_AF_INET6, { IN6ADDR_ANY_INIT } }; 
52const tr_address tr_inaddr_any = { TR_AF_INET, 
53    { { { { INADDR_ANY, 0x00, 0x00, 0x00 } } } } }; 
54
55
56void
57tr_netInit( void )
58{
59    static int initialized = FALSE;
60
61    if( !initialized )
62    {
63#ifdef WIN32
64        WSADATA wsaData;
65        WSAStartup( MAKEWORD( 2, 2 ), &wsaData );
66#endif
67        initialized = TRUE;
68    }
69}
70
71void
72tr_suspectAddress( const tr_address * a, const char * source )
73{
74    /* be really aggressive in what we report */
75    if( a->type == TR_AF_INET && !( a->addr.addr4.s_addr & 0xff000000 ) )
76        tr_dbg(  "Funny looking address %s from %s", tr_ntop_non_ts( a ), source );
77    /* /16s taken from ipv6 rib on 21 dec, 2008 */
78    /* this is really, really ugly. expedience over quality */
79    if( a->type == TR_AF_INET6 )
80    {
81        uint16_t slash16;
82        uint16_t valid[] = { 0x339, 0x2002, 0x2003, 0x2400, 0x2401, 0x2402,
83            0x2403, 0x2404, 0x2405, 0x2406, 0x2407, 0x2600, 0x2607, 0x2610,
84            0x2620, 0x2800, 0x2801, 0x2a00, 0x2a01, 0x0a02, 0x2001, 0x0000 };
85        uint16_t *p;
86        tr_bool good = FALSE;
87        p = valid;
88        memcpy( &slash16, &a->addr, 2 );
89        slash16 = ntohs( slash16 );
90        while( *p )
91        {
92            if( slash16 == *p )
93                good = TRUE;
94            p++;
95        }
96        if( !good )
97            tr_dbg(  "Funny looking address %s from %s", tr_ntop_non_ts( a ), source );
98    }
99}
100
101tr_bool
102tr_isAddress( const tr_address * a )
103{
104    return a && ( a->type==TR_AF_INET || a->type==TR_AF_INET6 );
105}
106
107const char * 
108tr_ntop( const tr_address * src, char * dst, int size ) 
109{
110    assert( tr_isAddress( src ) );
111
112    if( src->type == TR_AF_INET ) 
113        return inet_ntop( AF_INET, &src->addr, dst, size ); 
114    else 
115        return inet_ntop( AF_INET6, &src->addr, dst, size ); 
116} 
117
118/*
119 * Non-threadsafe version of tr_ntop, which uses a static memory area for a buffer.
120 * This function is suitable to be called from libTransmission's networking code,
121 * which is single-threaded.
122 */ 
123const char * 
124tr_ntop_non_ts( const tr_address * src ) 
125{ 
126    static char buf[INET6_ADDRSTRLEN]; 
127    return tr_ntop( src, buf, sizeof( buf ) ); 
128} 
129
130tr_address * 
131tr_pton( const char * src, tr_address * dst ) 
132{ 
133    int retval = inet_pton( AF_INET, src, &dst->addr ); 
134    if( retval < 0 ) 
135        return NULL; 
136    else if( retval == 0 ) 
137        retval = inet_pton( AF_INET6, src, &dst->addr ); 
138    else
139    { 
140        dst->type = TR_AF_INET; 
141        return dst; 
142    } 
143
144    if( retval < 1 ) 
145        return NULL; 
146    dst->type = TR_AF_INET6; 
147    return dst; 
148}
149
150void
151tr_normalizeV4Mapped( tr_address * const addr )
152{
153    assert( tr_isAddress( addr ) );
154
155    if( addr->type == TR_AF_INET6 && IN6_IS_ADDR_V4MAPPED( &addr->addr.addr6 ) )
156    {
157        addr->type = TR_AF_INET;
158        memcpy( &addr->addr.addr4.s_addr, addr->addr.addr6.s6_addr + 12, 4 );
159    }
160}
161
162/*
163 * Compare two tr_address structures.
164 * Returns:
165 * <0 if a < b
166 * >0 if a > b
167 * 0  if a == b
168 */ 
169int
170tr_compareAddresses( const tr_address * a, const tr_address * b)
171{
172    int addrlen;
173
174    assert( tr_isAddress( a ) );
175    assert( tr_isAddress( b ) );
176
177    /* IPv6 addresses are always "greater than" IPv4 */ 
178    if( a->type != b->type )
179        return a->type == TR_AF_INET ? 1 : -1;
180
181    if( a->type == TR_AF_INET ) 
182        addrlen = sizeof( struct in_addr ); 
183    else 
184        addrlen = sizeof( struct in6_addr ); 
185    return memcmp( &a->addr, &b->addr, addrlen );
186} 
187
188tr_net_af_support
189tr_net_getAFSupport( tr_port port )
190{
191    /* Do we care if an address is in use? Probably not, since it will be
192     * caught later. This will only set up the list of sockets to bind. */
193    static tr_bool alreadyDone       = FALSE;
194    static tr_net_af_support support = { FALSE, FALSE };
195    int s4, s6;
196    if( alreadyDone )
197        return support;
198    s6 = tr_netBindTCP( &tr_in6addr_any, port, TRUE );
199    if( s6 >= 0 || -s6 != EAFNOSUPPORT ) /* we support ipv6 */
200    {
201        listen( s6, 1 );
202        support.has_inet6 = TRUE;
203    }
204    s4 = tr_netBindTCP( &tr_inaddr_any, port, TRUE );
205    if( s4 >= 0 ) /* we bound *with* the ipv6 socket bound (need both)
206                   * or only have ipv4 */
207    {
208        tr_netClose( s4 );
209        support.needs_inet4 = TRUE;
210    }
211    if( s6 >= 0 )
212        tr_netClose( s6 );
213    alreadyDone = TRUE;
214    return support;
215}
216
217/***********************************************************************
218 * Socket list housekeeping
219 **********************************************************************/
220struct tr_socketList
221{
222    int             socket;
223    tr_address      addr;
224    tr_socketList * next;
225};
226
227tr_socketList *
228tr_socketListAppend( tr_socketList * const head,
229                     const tr_address * const addr )
230{
231    tr_socketList * tmp;
232
233    assert( head );
234    assert( tr_isAddress( addr ) );
235
236    for( tmp = head; tmp->next; tmp = tmp->next );
237    tmp->next = tr_socketListNew( addr );
238    return tmp->next;
239}
240
241tr_socketList *
242tr_socketListNew( const tr_address * const addr )
243{
244    tr_socketList * tmp;
245
246    assert( tr_isAddress( addr ) );
247
248    tmp = tr_new( tr_socketList, 1 );
249    tmp->socket = -1;
250    tmp->addr = *addr;
251    tmp->next = NULL;
252    return tmp;
253}
254
255void
256tr_socketListFree( tr_socketList * const head )
257{
258    assert( head );
259
260    if( head->next )
261        tr_socketListFree( head->next );
262    tr_free( head );
263}
264
265void
266tr_socketListRemove( tr_socketList * const head,
267                     tr_socketList * const el)
268{
269    tr_socketList * tmp;
270
271    assert( head );
272    assert( el );
273
274    for( tmp = head; tmp->next && tmp->next != el; tmp = tmp->next );
275    tmp->next = el->next;
276    el->next = NULL;
277    tr_socketListFree(el);
278}
279
280void
281tr_socketListTruncate( tr_socketList * const head,
282                       tr_socketList * const start )
283{
284    tr_socketList * tmp;
285
286    assert( head );
287    assert( start );
288
289    for( tmp = head; tmp->next && tmp->next != start; tmp = tmp->next );
290    tr_socketListFree( start );
291    tmp->next = NULL;
292}
293
294#if 0
295int
296tr_socketListGetSocket( const tr_socketList * const el )
297{
298    assert( el );
299
300    return el->socket;
301}
302
303const tr_address *
304tr_socketListGetAddress( const tr_socketList * const el )
305{
306    assert( el );
307    return &el->addr;
308}
309#endif
310
311void
312tr_socketListForEach( tr_socketList * const head,
313                      void ( * cb ) ( int * const,
314                                      tr_address * const,
315                                      void * const),
316                      void * const userData )
317{
318    tr_socketList * tmp;
319    for( tmp = head; tmp; tmp = tmp->next )
320        cb( &tmp->socket, &tmp->addr, userData );
321}
322
323/***********************************************************************
324 * TCP sockets
325 **********************************************************************/
326
327int
328tr_netSetTOS( int s, int tos )
329{
330#ifdef IP_TOS
331    return setsockopt( s, IPPROTO_IP, IP_TOS, (char*)&tos, sizeof( tos ) );
332#else
333    return 0;
334#endif
335}
336
337static int
338makeSocketNonBlocking( int fd )
339{
340    if( fd >= 0 )
341    {
342        if( evutil_make_socket_nonblocking( fd ) )
343        {
344            int tmperrno;
345            tr_err( _( "Couldn't create socket: %s" ),
346                   tr_strerror( sockerrno ) );
347            tmperrno = sockerrno;
348            tr_netClose( fd );
349            fd = -tmperrno;
350        }
351    }
352
353    return fd;
354}
355
356static int
357createSocket( int domain, int type )
358{
359    return makeSocketNonBlocking( tr_fdSocketCreate( domain, type ) );
360}
361
362static void
363setSndBuf( tr_session * session UNUSED, int fd UNUSED )
364{
365#if 0
366    if( fd >= 0 )
367    {
368        const int sndbuf = session->so_sndbuf;
369        const int rcvbuf = session->so_rcvbuf;
370        setsockopt( fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof( sndbuf ) );
371        setsockopt( fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof( rcvbuf ) );
372    }
373#endif
374}
375
376static socklen_t
377setup_sockaddr( const tr_address        * addr,
378                tr_port                   port,
379                struct sockaddr_storage * sockaddr)
380{
381    struct sockaddr_in  sock4;
382    struct sockaddr_in6 sock6;
383
384    assert( tr_isAddress( addr ) );
385
386    if( addr->type == TR_AF_INET )
387    {
388        memset( &sock4, 0, sizeof( sock4 ) );
389        sock4.sin_family      = AF_INET;
390        sock4.sin_addr.s_addr = addr->addr.addr4.s_addr;
391        sock4.sin_port        = port;
392        memcpy( sockaddr, &sock4, sizeof( sock4 ) );
393        return sizeof( struct sockaddr_in );
394    }
395    else
396    {
397        memset( &sock6, 0, sizeof( sock6 ) );
398        sock6.sin6_family = AF_INET6;
399        sock6.sin6_port = port;
400        sock6.sin6_flowinfo = 0;
401        sock6.sin6_addr = addr->addr.addr6;
402        memcpy( sockaddr, &sock6, sizeof( sock6 ) );
403        return sizeof( struct sockaddr_in6 );
404    }
405}
406
407int
408tr_netOpenTCP( tr_session        * session,
409               const tr_address  * addr,
410               tr_port             port )
411{
412    int                     s;
413    struct sockaddr_storage sock;
414    const int               type = SOCK_STREAM;
415    socklen_t               addrlen;
416
417    assert( tr_isAddress( addr ) );
418
419    if( ( s = createSocket( ( addr->type == TR_AF_INET ? AF_INET : AF_INET6 ),
420                            type ) ) < 0 )
421        return s;
422
423    setSndBuf( session, s );
424
425    addrlen = setup_sockaddr( addr, port, &sock );
426
427    if( ( connect( s, (struct sockaddr *) &sock,
428                  addrlen ) < 0 )
429#ifdef WIN32
430      && ( sockerrno != WSAEWOULDBLOCK )
431#endif
432      && ( sockerrno != EINPROGRESS ) )
433    {
434        int tmperrno;
435        tmperrno = sockerrno;
436        if( tmperrno != ENETUNREACH || addr->type == TR_AF_INET )
437            tr_err( _( "Couldn't connect socket %d to %s, port %d (errno %d - %s)" ),
438                    s, tr_ntop_non_ts( addr ), (int)port, tmperrno,
439                    tr_strerror( tmperrno ) );
440        tr_netClose( s );
441        s = -tmperrno;
442    }
443
444    tr_deepLog( __FILE__, __LINE__, NULL, "New OUTGOING connection %d (%s)",
445               s, tr_peerIoAddrStr( addr, port ) );
446
447    return s;
448}
449
450int
451tr_netBindTCP( const tr_address * addr, tr_port port, tr_bool suppressMsgs )
452{
453    int                     s;
454    struct sockaddr_storage sock;
455    const int               type = SOCK_STREAM;
456    int                     addrlen;
457
458#if defined( SO_REUSEADDR ) || defined( SO_REUSEPORT )
459    int                optval;
460#endif
461
462    assert( tr_isAddress( addr ) );
463
464    if( ( s = createSocket( ( addr->type == TR_AF_INET ? AF_INET : AF_INET6 ),
465                            type ) ) < 0 )
466        return s;
467
468#ifdef SO_REUSEADDR
469    optval = 1;
470    setsockopt( s, SOL_SOCKET, SO_REUSEADDR, (char*)&optval, sizeof( optval ) );
471#endif
472
473    addrlen = setup_sockaddr( addr, htons( port ), &sock );
474
475    if( bind( s, (struct sockaddr *) &sock,
476             addrlen ) )
477    {
478        int tmperrno;
479        if( !suppressMsgs )
480            tr_err( _( "Couldn't bind port %d on %s: %s" ), port,
481                    tr_ntop_non_ts( addr ), tr_strerror( sockerrno ) );
482        tmperrno = sockerrno;
483        tr_netClose( s );
484        return -tmperrno;
485    }
486    if( !suppressMsgs )
487        tr_dbg(  "Bound socket %d to port %d on %s",
488                 s, port, tr_ntop_non_ts( addr ) );
489    return s;
490}
491
492int
493tr_netAccept( tr_session  * session,
494              int           b,
495              tr_address  * addr,
496              tr_port     * port )
497{
498    int fd;
499
500    fd = makeSocketNonBlocking( tr_fdSocketAccept( b, addr, port ) );
501    setSndBuf( session, fd );
502    return fd;
503}
504
505void
506tr_netClose( int s )
507{
508    tr_fdSocketClose( s );
509}
Note: See TracBrowser for help on using the repository browser.