source: trunk/libtransmission/net.c @ 218

Last change on this file since 218 was 218, checked in by titer, 16 years ago

Fixed a couple of bugs introduced in [164]

File size: 6.9 KB
Line 
1/******************************************************************************
2 * Copyright (c) 2005-2006 Transmission authors and contributors
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 *****************************************************************************/
22
23#include "transmission.h"
24
25static int makeSocketNonBlocking( int s )
26{
27    int flags;
28
29#ifdef SYS_BEOS
30    flags = 1;
31    if( setsockopt( s, SOL_SOCKET, SO_NONBLOCK,
32                    &flags, sizeof( int ) ) < 0 )
33#else
34    if( ( flags = fcntl( s, F_GETFL, 0 ) ) < 0 ||
35        fcntl( s, F_SETFL, flags | O_NONBLOCK ) < 0 )
36#endif
37    {
38        tr_err( "Could not set socket to non-blocking mode (%s)",
39                strerror( errno ) );
40        tr_netClose( s );
41        return -1;
42    }
43
44    return s;
45}
46
47static int createSocket()
48{
49    int s;
50
51    s = socket( AF_INET, SOCK_STREAM, 0 );
52    if( s < 0 )
53    {
54        tr_err( "Could not create socket (%s)", strerror( errno ) );
55        return -1;
56    }
57
58    return makeSocketNonBlocking( s );
59}
60
61struct tr_resolve_s
62{
63    int            status;
64    char           * address;
65    struct in_addr addr;
66
67    tr_lock_t      lock;
68    tr_thread_t    thread;
69    int            orphan;
70};
71
72/* Hem, global variable. Initialized from tr_init(). */
73tr_lock_t gethostbynameLock;
74
75static void resolveFunc( void * _r )
76{
77    tr_resolve_t * r = _r;
78    struct hostent * host;
79
80    tr_lockLock( &r->lock );
81
82    r->addr.s_addr = inet_addr( r->address );
83    if( r->addr.s_addr != 0xFFFFFFFF )
84    {
85        /* This was an IP address, no resolving required */
86        r->status = TR_RESOLVE_OK;
87        goto resolveDone;
88    }
89
90    tr_lockLock( &gethostbynameLock );
91    tr_lockUnlock( &r->lock );
92    host = gethostbyname( r->address );
93    tr_lockLock( &r->lock );
94    if( host )
95    {
96        memcpy( &r->addr, host->h_addr, host->h_length );
97        r->status = TR_RESOLVE_OK;
98    }
99    else
100    {
101        r->status = TR_RESOLVE_ERROR;
102    }
103    tr_lockUnlock( &gethostbynameLock );
104
105resolveDone:
106    if( r->orphan )
107    {
108        /* tr_netResolveClose was closed already. Free memory */
109        tr_lockUnlock( &r->lock );
110        tr_lockClose( &r->lock );
111        free( r );
112    }
113    else
114    {
115        tr_lockUnlock( &r->lock );
116    }
117}
118
119tr_resolve_t * tr_netResolveInit( char * address )
120{
121    tr_resolve_t * r = malloc( sizeof( tr_resolve_t ) );
122
123    r->status  = TR_RESOLVE_WAIT;
124    r->address = address;
125
126    tr_lockInit( &r->lock );
127    tr_threadCreate( &r->thread, resolveFunc, r );
128    r->orphan = 0;
129
130    return r;
131}
132
133int tr_netResolvePulse( tr_resolve_t * r, struct in_addr * addr )
134{
135    int ret;
136
137    tr_lockLock( &r->lock );
138    ret = r->status;
139    if( ret == TR_RESOLVE_OK )
140    {
141        *addr = r->addr;
142    }
143    tr_lockUnlock( &r->lock );
144
145    return ret;
146}
147
148void tr_netResolveClose( tr_resolve_t * r )
149{
150    tr_lockLock( &r->lock );
151    if( r->status == TR_RESOLVE_WAIT )
152    {
153        /* Let the thread die */
154        r->orphan = 1;
155        tr_lockUnlock( &r->lock );
156        return;
157    }
158    tr_lockUnlock( &r->lock );
159
160    /* Clean up */
161    tr_threadJoin( &r->thread );
162    tr_lockClose( &r->lock );
163    free( r );
164}
165
166/* Blocking version */
167int tr_netResolve( char * address, struct in_addr * addr )
168{
169    tr_resolve_t * r = tr_netResolveInit( address );
170    int ret;
171
172    for( ;; )
173    {
174        ret = tr_netResolvePulse( r, addr );
175        if( ret != TR_RESOLVE_WAIT )
176        {
177            break;
178        }
179        tr_wait( 20 );
180    }
181
182    tr_netResolveClose( r );
183    return ( ret != TR_RESOLVE_OK );
184}
185
186int tr_netOpen( struct in_addr addr, in_port_t port )
187{
188    int s;
189    struct sockaddr_in sock;
190
191    s = createSocket();
192    if( s < 0 )
193    {
194        return -1;
195    }
196
197    memset( &sock, 0, sizeof( sock ) );
198    sock.sin_family      = AF_INET;
199    sock.sin_addr.s_addr = addr.s_addr;
200    sock.sin_port        = port;
201
202    if( connect( s, (struct sockaddr *) &sock,
203                 sizeof( struct sockaddr_in ) ) < 0 &&
204        errno != EINPROGRESS )
205    {
206        tr_err( "Could not connect socket (%s)", strerror( errno ) );
207        tr_netClose( s );
208        return -1;
209    }
210
211    return s;
212}
213
214int tr_netBind( int port )
215{
216    int s;
217    struct sockaddr_in sock;
218#ifdef SO_REUSEADDR
219    int optval;
220#endif
221
222    s = createSocket();
223    if( s < 0 )
224    {
225        return -1;
226    }
227
228#ifdef SO_REUSEADDR
229    optval = 1;
230    setsockopt( s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof( optval ) );
231#endif
232
233    memset( &sock, 0, sizeof( sock ) );
234    sock.sin_family      = AF_INET;
235    sock.sin_addr.s_addr = INADDR_ANY;
236    sock.sin_port        = htons( port );
237
238    if( bind( s, (struct sockaddr *) &sock,
239               sizeof( struct sockaddr_in ) ) )
240    {
241        tr_err( "Could not bind port %d", port );
242        tr_netClose( s );
243        return -1;
244    }
245   
246    tr_inf( "Binded port %d", port );
247    listen( s, 5 );
248
249    return s;
250}
251
252int tr_netAccept( int s, struct in_addr * addr, in_port_t * port )
253{
254    int t;
255    unsigned len;
256    struct sockaddr_in sock;
257
258    len = sizeof( sock );
259    t   = accept( s, (struct sockaddr *) &sock, &len );
260
261    if( t < 0 )
262    {
263        return -1;
264    }
265   
266    *addr = sock.sin_addr;
267    *port = sock.sin_port;
268
269    return makeSocketNonBlocking( t );
270}
271
272int tr_netSend( int s, uint8_t * buf, int size )
273{
274    int ret;
275
276    ret = send( s, buf, size, 0 );
277    if( ret < 0 )
278    {
279        if( errno == ENOTCONN || errno == EAGAIN || errno == EWOULDBLOCK )
280        {
281            ret = TR_NET_BLOCK;
282        }
283        else
284        {
285            ret = TR_NET_CLOSE;
286        }
287    }
288
289    return ret;
290}
291
292int tr_netRecv( int s, uint8_t * buf, int size )
293{
294    int ret;
295
296    ret = recv( s, buf, size, 0 );
297    if( ret < 0 )
298    {
299        if( errno == EAGAIN || errno == EWOULDBLOCK )
300        {
301            ret = TR_NET_BLOCK;
302        }
303        else
304        {
305            ret = TR_NET_CLOSE;
306        }
307    }
308    if( !ret )
309    {
310        ret = TR_NET_CLOSE;
311    }
312
313    return ret;
314}
315
316void tr_netClose( int s )
317{
318#ifdef BEOS_NETSERVER
319    closesocket( s );
320#else
321    close( s );
322#endif
323}
Note: See TracBrowser for help on using the repository browser.