source: trunk/libtransmission/net.c @ 3171

Last change on this file since 3171 was 3171, checked in by charles, 15 years ago
  • record the ports of incoming sockets. we might need them later if we want to disconnect and reconnect.
  • for portability, use libevent API for some socket upkeep
  • Property svn:keywords set to Date Rev Author Id
File size: 7.0 KB
Line 
1/******************************************************************************
2 * $Id: net.c 3171 2007-09-25 23:10:34Z charles $
3 *
4 * Copyright (c) 2005-2006 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
30#include <sys/types.h>
31
32#ifndef WIN32
33#include <netdb.h>
34#include <fcntl.h>
35#endif
36
37#include <evutil.h>
38
39#include "transmission.h"
40#include "fdlimit.h"
41#include "net.h"
42#include "platform.h"
43#include "utils.h"
44
45
46void
47tr_netInit( void )
48{
49    static int initialized = FALSE;
50    if( !initialized )
51    {
52#ifdef WIN32
53        WSADATA wsaData;
54        WSAStartup(MAKEWORD(2,2), &wsaData);
55#endif
56        initialized = TRUE;
57    }
58}
59
60/***********************************************************************
61 * DNS resolution
62 *
63 * Synchronous "resolution": only works with character strings
64 * representing numbers expressed in the Internet standard `.' notation.
65 * Returns a non-zero value if an error occurs.
66 **********************************************************************/
67int tr_netResolve( const char * address, struct in_addr * addr )
68{
69    addr->s_addr = inet_addr( address );
70    return ( addr->s_addr == 0xFFFFFFFF );
71}
72
73
74/***********************************************************************
75 * TCP/UDP sockets
76 **********************************************************************/
77
78static int
79makeSocketNonBlocking( int fd )
80{
81    if( fd >= 0 )
82    {
83#if defined(__BEOS__)
84        int flags = 1;
85        if( setsockopt( fd, SOL_SOCKET, SO_NONBLOCK,
86                        &flags, sizeof( int ) ) < 0 )
87#else
88        if( evutil_make_socket_nonblocking( fd ) )
89#endif
90        {
91            tr_err( "Couldn't set socket to non-blocking mode (%s)",
92                    strerror( sockerrno ) );
93            tr_netClose( fd );
94            fd = -1;
95        }
96    }
97
98    return fd;
99}
100
101static int
102createSocket( int type, int priority )
103{
104    return makeSocketNonBlocking( tr_fdSocketCreate( type, priority ) );
105}
106
107static int
108tr_netOpen( const struct in_addr * addr, tr_port_t port,
109            int type, int priority )
110{
111    int s;
112    struct sockaddr_in sock;
113
114    if( ( s = createSocket( type, priority ) ) < 0 )
115    {
116        return -1;
117    }
118
119    memset( &sock, 0, sizeof( sock ) );
120    sock.sin_family      = AF_INET;
121    sock.sin_addr.s_addr = addr->s_addr;
122    sock.sin_port        = port;
123
124    if( ( connect( s, (struct sockaddr *) &sock,
125                   sizeof( struct sockaddr_in ) ) < 0 )
126#ifdef WIN32
127        && ( sockerrno != WSAEWOULDBLOCK )
128#endif
129        && ( sockerrno != EINPROGRESS ) )
130    {
131        tr_err( "Couldn't connect socket (%s)", strerror( sockerrno ) );
132        tr_netClose( s );
133        return -1;
134    }
135
136    return s;
137}
138 
139int
140tr_netOpenTCP( const struct in_addr * addr, tr_port_t port, int priority )
141{
142    return tr_netOpen( addr, port, SOCK_STREAM, priority );
143}
144
145int
146tr_netOpenUDP( const struct in_addr * addr, tr_port_t port, int priority )
147{
148    return tr_netOpen( addr, port, SOCK_DGRAM, priority );
149}
150
151#ifdef IP_ADD_MEMBERSHIP
152int tr_netMcastOpen( int port, const struct in_addr * addr )
153{
154    int fd;
155    struct ip_mreq req;
156
157    fd = tr_netBindUDP( port );
158    if( 0 > fd )
159    {
160        return -1;
161    }
162
163    memset( &req, 0, sizeof( req ) );
164    req.imr_multiaddr.s_addr = addr->s_addr;
165    req.imr_interface.s_addr = htonl( INADDR_ANY );
166    if( setsockopt( fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&req, sizeof ( req ) ) )
167    {
168        tr_err( "Couldn't join multicast group (%s)", strerror( sockerrno ) );
169        tr_netClose( fd );
170        return -1;
171    }
172
173    return fd;
174}
175#else /* IP_ADD_MEMBERSHIP */
176int tr_netMcastOpen( int port UNUSED, const struct in_addr * addr UNUSED )
177{
178    return -1;
179}
180#endif /* IP_ADD_MEMBERSHIP */
181
182static int
183tr_netBind( int port, int type )
184{
185    int s;
186    struct sockaddr_in sock;
187#if defined( SO_REUSEADDR ) || defined( SO_REUSEPORT )
188    int optval;
189#endif
190
191    if( ( s = createSocket( type, 1 ) ) < 0 )
192    {
193        return -1;
194    }
195
196#ifdef SO_REUSEADDR
197    optval = 1;
198    setsockopt( s, SOL_SOCKET, SO_REUSEADDR, (char*)&optval, sizeof( optval ) );
199#endif
200
201#ifdef SO_REUSEPORT
202    if( SOCK_DGRAM == type )
203    {
204        optval = 1;
205        setsockopt( s, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof( optval ) );
206    }
207#endif
208
209    memset( &sock, 0, sizeof( sock ) );
210    sock.sin_family      = AF_INET;
211    sock.sin_addr.s_addr = INADDR_ANY;
212    sock.sin_port        = htons( port );
213
214    if( bind( s, (struct sockaddr *) &sock,
215               sizeof( struct sockaddr_in ) ) )
216    {
217        tr_err( "Couldn't bind port %d", port );
218        tr_netClose( s );
219        return -1;
220    }
221
222    return s;
223}
224
225int
226tr_netBindTCP( int port )
227{
228    return tr_netBind( port, SOCK_STREAM );
229}
230
231int
232tr_netBindUDP( int port )
233{
234    return tr_netBind( port, SOCK_DGRAM );
235}
236
237
238int
239tr_netAccept( int b, struct in_addr * addr, tr_port_t * port )
240{
241    return makeSocketNonBlocking( tr_fdSocketAccept( b, addr, port ) );
242}
243
244int
245tr_netSend( int s, const void * buf, int size )
246{
247    const int ret = send( s, buf, size, 0 );
248    if( ret >= 0 )
249        return ret;
250
251    if( sockerrno == ENOTCONN || sockerrno == EAGAIN || sockerrno == EWOULDBLOCK )
252        return TR_NET_BLOCK;
253
254    return TR_NET_CLOSE;
255}
256
257int tr_netRecvFrom( int s, uint8_t * buf, int size, struct sockaddr_in * addr )
258{
259    socklen_t len;
260    int       ret;
261
262    len = ( NULL == addr ? 0 : sizeof( *addr ) );
263    ret = recvfrom( s, buf, size, 0, ( struct sockaddr * ) addr, &len );
264    if( ret < 0 )
265    {
266        if( sockerrno == EAGAIN || sockerrno == EWOULDBLOCK )
267        {
268            ret = TR_NET_BLOCK;
269        }
270        else
271        {
272            ret = TR_NET_CLOSE;
273        }
274    }
275    if( !ret )
276    {
277        ret = TR_NET_CLOSE;
278    }
279
280    return ret;
281}
282
283void
284tr_netClose( int s )
285{
286    tr_fdSocketClose( s );
287}
288
289void
290tr_netNtop( const struct in_addr * addr, char * buf, int len )
291{
292    const uint8_t * cast;
293
294    cast = (const uint8_t *)addr;
295    snprintf( buf, len, "%hhu.%hhu.%hhu.%hhu",
296              cast[0], cast[1], cast[2], cast[3] );
297}
Note: See TracBrowser for help on using the repository browser.