source: trunk/libtransmission/net.c @ 7417

Last change on this file since 7417 was 7417, checked in by jhujhiti, 12 years ago

fix another bad assert *eyes charles*

  • Property svn:keywords set to Date Rev Author Id
File size: 11.0 KB
Line 
1/******************************************************************************
2 * $Id: net.c 7417 2008-12-16 21:44:53Z 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
71tr_bool
72tr_isAddress( const tr_address * a )
73{
74    return a && ( a->type==TR_AF_INET || a->type==TR_AF_INET6 );
75}
76
77const char * 
78tr_ntop( const tr_address * src, char * dst, int size ) 
79{
80    assert( tr_isAddress( src ) );
81
82    if( src->type == TR_AF_INET ) 
83        return inet_ntop( AF_INET, &src->addr, dst, size ); 
84    else 
85        return inet_ntop( AF_INET6, &src->addr, dst, size ); 
86} 
87
88/*
89 * Non-threadsafe version of tr_ntop, which uses a static memory area for a buffer.
90 * This function is suitable to be called from libTransmission's networking code,
91 * which is single-threaded.
92 */ 
93const char * 
94tr_ntop_non_ts( const tr_address * src ) 
95{ 
96    static char buf[INET6_ADDRSTRLEN]; 
97    return tr_ntop( src, buf, sizeof( buf ) ); 
98} 
99
100tr_address * 
101tr_pton( const char * src, tr_address * dst ) 
102{ 
103    int retval = inet_pton( AF_INET, src, &dst->addr ); 
104    if( retval < 0 ) 
105        return NULL; 
106    else if( retval == 0 ) 
107        retval = inet_pton( AF_INET6, src, &dst->addr ); 
108    else
109    { 
110        dst->type = TR_AF_INET; 
111        return dst; 
112    } 
113
114    if( retval < 1 ) 
115        return NULL; 
116    dst->type = TR_AF_INET6; 
117    return dst; 
118}
119
120void
121tr_normalizeV4Mapped( tr_address * const addr )
122{
123    assert( tr_isAddress( addr ) );
124
125    if( addr->type == TR_AF_INET6 && IN6_IS_ADDR_V4MAPPED( &addr->addr.addr6 ) )
126    {
127        addr->type = TR_AF_INET;
128        memcpy( &addr->addr.addr4.s_addr, addr->addr.addr6.s6_addr + 12, 4 );
129    }
130}
131
132/*
133 * Compare two tr_address structures.
134 * Returns:
135 * <0 if a < b
136 * >0 if a > b
137 * 0  if a == b
138 */ 
139int
140tr_compareAddresses( const tr_address * a, const tr_address * b)
141{
142    int addrlen;
143
144    assert( tr_isAddress( a ) );
145    assert( tr_isAddress( b ) );
146
147    /* IPv6 addresses are always "greater than" IPv4 */ 
148    if( a->type != b->type )
149        return a->type == TR_AF_INET ? 1 : -1;
150
151    if( a->type == TR_AF_INET ) 
152        addrlen = sizeof( struct in_addr ); 
153    else 
154        addrlen = sizeof( struct in6_addr ); 
155    return memcmp( &a->addr, &b->addr, addrlen );
156} 
157
158/***********************************************************************
159 * Socket list housekeeping
160 **********************************************************************/
161struct tr_socketList
162{
163    int             socket;
164    tr_address      addr;
165    tr_socketList * next;
166};
167
168tr_socketList *
169tr_socketListAppend( tr_socketList * const head,
170                     const tr_address * const addr )
171{
172    tr_socketList * tmp;
173
174    assert( head );
175    assert( tr_isAddress( addr ) );
176
177    for( tmp = head; tmp->next; tmp = tmp->next );
178    tmp->next = tr_socketListNew( addr );
179    return tmp->next;
180}
181
182tr_socketList *
183tr_socketListNew( const tr_address * const addr )
184{
185    tr_socketList * tmp;
186
187    assert( tr_isAddress( addr ) );
188
189    tmp = tr_new( tr_socketList, 1 );
190    tmp->socket = -1;
191    tmp->addr = *addr;
192    tmp->next = NULL;
193    return tmp;
194}
195
196void
197tr_socketListFree( tr_socketList * const head )
198{
199    assert( head );
200
201    if( head->next )
202        tr_socketListFree( head->next );
203    tr_free( head );
204}
205
206void
207tr_socketListRemove( tr_socketList * const head,
208                     tr_socketList * const el)
209{
210    tr_socketList * tmp;
211
212    assert( head );
213    assert( el );
214
215    for( tmp = head; tmp->next && tmp->next != el; tmp = tmp->next );
216    tmp->next = el->next;
217    el->next = NULL;
218    tr_socketListFree(el);
219}
220
221void
222tr_socketListTruncate( tr_socketList * const head,
223                       tr_socketList * const start )
224{
225    tr_socketList * tmp;
226
227    assert( head );
228    assert( start );
229
230    for( tmp = head; tmp->next && tmp->next != start; tmp = tmp->next );
231    tr_socketListFree( start );
232    tmp->next = NULL;
233}
234
235#if 0
236int
237tr_socketListGetSocket( const tr_socketList * const el )
238{
239    assert( el );
240
241    return el->socket;
242}
243
244const tr_address *
245tr_socketListGetAddress( const tr_socketList * const el )
246{
247    assert( el );
248    return &el->addr;
249}
250#endif
251
252void
253tr_socketListForEach( tr_socketList * const head,
254                      void ( * cb ) ( int * const,
255                                      tr_address * const,
256                                      void * const),
257                      void * const userData )
258{
259    tr_socketList * tmp;
260    for( tmp = head; tmp; tmp = tmp->next )
261        cb( &tmp->socket, &tmp->addr, userData );
262}
263
264/***********************************************************************
265 * TCP sockets
266 **********************************************************************/
267
268int
269tr_netSetTOS( int s, int tos )
270{
271#ifdef IP_TOS
272    return setsockopt( s, IPPROTO_IP, IP_TOS, (char*)&tos, sizeof( tos ) );
273#else
274    return 0;
275#endif
276}
277
278static int
279makeSocketNonBlocking( int fd )
280{
281    if( fd >= 0 )
282    {
283        if( evutil_make_socket_nonblocking( fd ) )
284        {
285            int tmperrno;
286            tr_err( _( "Couldn't create socket: %s" ),
287                   tr_strerror( sockerrno ) );
288            tmperrno = sockerrno;
289            tr_netClose( fd );
290            fd = -tmperrno;
291        }
292    }
293
294    return fd;
295}
296
297static int
298createSocket( int domain, int type )
299{
300    return makeSocketNonBlocking( tr_fdSocketCreate( domain, type ) );
301}
302
303static void
304setSndBuf( tr_session * session UNUSED, int fd UNUSED )
305{
306#if 0
307    if( fd >= 0 )
308    {
309        const int sndbuf = session->so_sndbuf;
310        const int rcvbuf = session->so_rcvbuf;
311        setsockopt( fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof( sndbuf ) );
312        setsockopt( fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof( rcvbuf ) );
313    }
314#endif
315}
316
317static socklen_t
318setup_sockaddr( const tr_address        * addr,
319                tr_port                   port,
320                struct sockaddr_storage * sockaddr)
321{
322    struct sockaddr_in  sock4;
323    struct sockaddr_in6 sock6;
324
325    assert( tr_isAddress( addr ) );
326
327    if( addr->type == TR_AF_INET )
328    {
329        memset( &sock4, 0, sizeof( sock4 ) );
330        sock4.sin_family      = AF_INET;
331        sock4.sin_addr.s_addr = addr->addr.addr4.s_addr;
332        sock4.sin_port        = port;
333        memcpy( sockaddr, &sock4, sizeof( sock4 ) );
334        return sizeof( struct sockaddr_in );
335    }
336    else
337    {
338        memset( &sock6, 0, sizeof( sock6 ) );
339        sock6.sin6_family = AF_INET6;
340        sock6.sin6_port = port;
341        sock6.sin6_flowinfo = 0;
342        sock6.sin6_addr = addr->addr.addr6;
343        memcpy( sockaddr, &sock6, sizeof( sock6 ) );
344        return sizeof( struct sockaddr_in6 );
345    }
346}
347
348int
349tr_netOpenTCP( tr_session        * session,
350               const tr_address  * addr,
351               tr_port             port )
352{
353    int                     s;
354    struct sockaddr_storage sock;
355    const int               type = SOCK_STREAM;
356    socklen_t               addrlen;
357
358    assert( tr_isAddress( addr ) );
359
360    if( ( s = createSocket( ( addr->type == TR_AF_INET ? AF_INET : AF_INET6 ),
361                            type ) ) < 0 )
362        return s;
363
364    setSndBuf( session, s );
365
366    addrlen = setup_sockaddr( addr, port, &sock );
367
368    if( ( connect( s, (struct sockaddr *) &sock,
369                  addrlen ) < 0 )
370#ifdef WIN32
371      && ( sockerrno != WSAEWOULDBLOCK )
372#endif
373      && ( sockerrno != EINPROGRESS ) )
374    {
375        int tmperrno;
376        tr_err( _( "Couldn't connect socket %d to %s, port %d (errno %d - %s)" ),
377               s, tr_ntop_non_ts( addr ), (int)port, sockerrno, tr_strerror( sockerrno ) );
378        tmperrno = sockerrno;
379        tr_netClose( s );
380        s = -tmperrno;
381    }
382
383    tr_deepLog( __FILE__, __LINE__, NULL, "New OUTGOING connection %d (%s)",
384               s, tr_peerIoAddrStr( addr, port ) );
385
386    return s;
387}
388
389int
390tr_netBindTCP( const tr_address * addr, tr_port port, tr_bool suppressMsgs )
391{
392    int                     s;
393    struct sockaddr_storage sock;
394    const int               type = SOCK_STREAM;
395    int                     addrlen;
396
397#if defined( SO_REUSEADDR ) || defined( SO_REUSEPORT )
398    int                optval;
399#endif
400
401    assert( tr_isAddress( addr ) );
402
403    if( ( s = createSocket( ( addr->type == TR_AF_INET ? AF_INET : AF_INET6 ),
404                            type ) ) < 0 )
405        return s;
406
407#ifdef SO_REUSEADDR
408    optval = 1;
409    setsockopt( s, SOL_SOCKET, SO_REUSEADDR, (char*)&optval, sizeof( optval ) );
410#endif
411
412    addrlen = setup_sockaddr( addr, htons( port ), &sock );
413
414    if( bind( s, (struct sockaddr *) &sock,
415             addrlen ) )
416    {
417        int tmperrno;
418        if( !suppressMsgs )
419            tr_err( _( "Couldn't bind port %d on %s: %s" ), port,
420                    tr_ntop_non_ts( addr ), tr_strerror( sockerrno ) );
421        tmperrno = sockerrno;
422        tr_netClose( s );
423        return -tmperrno;
424    }
425    if( !suppressMsgs )
426        tr_dbg(  "Bound socket %d to port %d on %s",
427                 s, port, tr_ntop_non_ts( addr ) );
428    return s;
429}
430
431int
432tr_netAccept( tr_session  * session,
433              int           b,
434              tr_address  * addr,
435              tr_port     * port )
436{
437    int fd;
438
439    fd = makeSocketNonBlocking( tr_fdSocketAccept( b, addr, port ) );
440    setSndBuf( session, fd );
441    return fd;
442}
443
444void
445tr_netClose( int s )
446{
447    tr_fdSocketClose( s );
448}
Note: See TracBrowser for help on using the repository browser.