source: trunk/libtransmission/net.c @ 7561

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

(trunk libT) Stop trying to connect to multicast addresses. Also, bump "funny
looking address" messages from tr_dbg to tr_err so I can get bug reports with
the message for once!

  • Property svn:keywords set to Date Rev Author Id
File size: 13.3 KB
Line 
1/******************************************************************************
2 * $Id: net.c 7561 2008-12-31 21:25: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_err(  "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_err(  "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    /* don't try to connect to multicast addresses */
420    if( addr->type == TR_AF_INET && ( addr->addr.addr4.s_addr & 0xe0000000 ) )
421        return -EINVAL;
422    if( addr->type == TR_AF_INET6 && ( addr->addr.addr6.s6_addr[0] & 0xff ) )
423        return -EINVAL;
424
425    if( ( s = createSocket( ( addr->type == TR_AF_INET ? AF_INET : AF_INET6 ),
426                            type ) ) < 0 )
427        return s;
428
429    setSndBuf( session, s );
430
431    addrlen = setup_sockaddr( addr, port, &sock );
432
433    if( ( connect( s, (struct sockaddr *) &sock,
434                  addrlen ) < 0 )
435#ifdef WIN32
436      && ( sockerrno != WSAEWOULDBLOCK )
437#endif
438      && ( sockerrno != EINPROGRESS ) )
439    {
440        int tmperrno;
441        tmperrno = sockerrno;
442        if( tmperrno != ENETUNREACH || addr->type == TR_AF_INET )
443            tr_err( _( "Couldn't connect socket %d to %s, port %d (errno %d - %s)" ),
444                    s, tr_ntop_non_ts( addr ), (int)port, tmperrno,
445                    tr_strerror( tmperrno ) );
446        tr_netClose( s );
447        s = -tmperrno;
448    }
449
450    tr_deepLog( __FILE__, __LINE__, NULL, "New OUTGOING connection %d (%s)",
451               s, tr_peerIoAddrStr( addr, port ) );
452
453    return s;
454}
455
456int
457tr_netBindTCP( const tr_address * addr, tr_port port, tr_bool suppressMsgs )
458{
459    int                     s;
460    struct sockaddr_storage sock;
461    const int               type = SOCK_STREAM;
462    int                     addrlen;
463
464#if defined( SO_REUSEADDR ) || defined( SO_REUSEPORT )
465    int                optval;
466#endif
467
468    assert( tr_isAddress( addr ) );
469
470    if( ( s = createSocket( ( addr->type == TR_AF_INET ? AF_INET : AF_INET6 ),
471                            type ) ) < 0 )
472        return s;
473
474#ifdef SO_REUSEADDR
475    optval = 1;
476    setsockopt( s, SOL_SOCKET, SO_REUSEADDR, (char*)&optval, sizeof( optval ) );
477#endif
478
479    addrlen = setup_sockaddr( addr, htons( port ), &sock );
480
481    if( bind( s, (struct sockaddr *) &sock,
482             addrlen ) )
483    {
484        int tmperrno;
485        if( !suppressMsgs )
486            tr_err( _( "Couldn't bind port %d on %s: %s" ), port,
487                    tr_ntop_non_ts( addr ), tr_strerror( sockerrno ) );
488        tmperrno = sockerrno;
489        tr_netClose( s );
490        return -tmperrno;
491    }
492    if( !suppressMsgs )
493        tr_dbg(  "Bound socket %d to port %d on %s",
494                 s, port, tr_ntop_non_ts( addr ) );
495    return s;
496}
497
498int
499tr_netAccept( tr_session  * session,
500              int           b,
501              tr_address  * addr,
502              tr_port     * port )
503{
504    int fd;
505
506    fd = makeSocketNonBlocking( tr_fdSocketAccept( b, addr, port ) );
507    setSndBuf( session, fd );
508    return fd;
509}
510
511void
512tr_netClose( int s )
513{
514    tr_fdSocketClose( s );
515}
Note: See TracBrowser for help on using the repository browser.