source: trunk/libtransmission/net.c @ 164

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

Adds non-blocking (threaded) DNS resolution

File size: 6.3 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};
70
71static void resolveFunc( void * _r )
72{
73    tr_resolve_t * r = _r;
74    struct hostent * host;
75
76    tr_lockLock( &r->lock );
77    r->addr.s_addr = inet_addr( r->address );
78    if( r->addr.s_addr != 0xFFFFFFFF )
79    {
80        r->status = TR_RESOLVE_OK;
81        tr_lockUnlock( &r->lock );
82        return;
83    }
84    tr_lockUnlock( &r->lock );
85
86    if( !( host = gethostbyname( r->address ) ) )
87    {
88        tr_lockLock( &r->lock );
89        r->status = TR_RESOLVE_ERROR;
90        tr_lockUnlock( &r->lock );
91        return;
92    }
93    tr_lockLock( &r->lock );
94    memcpy( &r->addr, host->h_addr, host->h_length );
95    r->status = TR_RESOLVE_OK;
96    tr_lockUnlock( &r->lock );
97}
98
99tr_resolve_t * tr_netResolveInit( char * address )
100{
101    tr_resolve_t * r = malloc( sizeof( tr_resolve_t ) );
102
103    r->status  = TR_RESOLVE_WAIT;
104    r->address = address;
105
106    tr_lockInit( &r->lock );
107    tr_threadCreate( &r->thread, resolveFunc, r );
108
109    return r;
110}
111
112int tr_netResolvePulse( tr_resolve_t * r, struct in_addr * addr )
113{
114    int ret;
115
116    tr_lockLock( &r->lock );
117    ret = r->status;
118    if( ret == TR_RESOLVE_OK )
119    {
120        *addr = r->addr;
121    }
122    tr_lockUnlock( &r->lock );
123
124    return ret;
125}
126
127void tr_netResolveClose( tr_resolve_t * r )
128{
129    tr_threadJoin( &r->thread );
130    tr_lockClose( &r->lock );
131    free( r );
132}
133
134/* Blocking version */
135int tr_netResolve( char * address, struct in_addr * addr )
136{
137    tr_resolve_t * r = tr_netResolveInit( address );
138    int ret;
139
140    for( ;; )
141    {
142        ret = tr_netResolvePulse( r, addr );
143        if( ret != TR_RESOLVE_WAIT )
144        {
145            break;
146        }
147        tr_wait( 20 );
148    }
149
150    tr_netResolveClose( r );
151    return ( ret != TR_RESOLVE_OK );
152}
153
154int tr_netOpen( struct in_addr addr, in_port_t port )
155{
156    int s;
157    struct sockaddr_in sock;
158
159    s = createSocket();
160    if( s < 0 )
161    {
162        return -1;
163    }
164
165    memset( &sock, 0, sizeof( sock ) );
166    sock.sin_family      = AF_INET;
167    sock.sin_addr.s_addr = addr.s_addr;
168    sock.sin_port        = port;
169
170    if( connect( s, (struct sockaddr *) &sock,
171                 sizeof( struct sockaddr_in ) ) < 0 &&
172        errno != EINPROGRESS )
173    {
174        tr_err( "Could not connect socket (%s)", strerror( errno ) );
175        tr_netClose( s );
176        return -1;
177    }
178
179    return s;
180}
181
182int tr_netBind( int port )
183{
184    int s;
185    struct sockaddr_in sock;
186#ifdef SO_REUSEADDR
187    int optval;
188#endif
189
190    s = createSocket();
191    if( s < 0 )
192    {
193        return -1;
194    }
195
196#ifdef SO_REUSEADDR
197    optval = 1;
198    setsockopt( s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof( optval ) );
199#endif
200
201    memset( &sock, 0, sizeof( sock ) );
202    sock.sin_family      = AF_INET;
203    sock.sin_addr.s_addr = INADDR_ANY;
204    sock.sin_port        = htons( port );
205
206    if( bind( s, (struct sockaddr *) &sock,
207               sizeof( struct sockaddr_in ) ) )
208    {
209        tr_err( "Could not bind port %d", port );
210        tr_netClose( s );
211        return -1;
212    }
213   
214    tr_inf( "Binded port %d", port );
215    listen( s, 5 );
216
217    return s;
218}
219
220int tr_netAccept( int s, struct in_addr * addr, in_port_t * port )
221{
222    int t;
223    unsigned len;
224    struct sockaddr_in sock;
225
226    len = sizeof( sock );
227    t   = accept( s, (struct sockaddr *) &sock, &len );
228
229    if( t < 0 )
230    {
231        return -1;
232    }
233   
234    *addr = sock.sin_addr;
235    *port = sock.sin_port;
236
237    return makeSocketNonBlocking( t );
238}
239
240int tr_netSend( int s, uint8_t * buf, int size )
241{
242    int ret;
243
244    ret = send( s, buf, size, 0 );
245    if( ret < 0 )
246    {
247        if( errno == ENOTCONN || errno == EAGAIN || errno == EWOULDBLOCK )
248        {
249            ret = TR_NET_BLOCK;
250        }
251        else
252        {
253            ret = TR_NET_CLOSE;
254        }
255    }
256
257    return ret;
258}
259
260int tr_netRecv( int s, uint8_t * buf, int size )
261{
262    int ret;
263
264    ret = recv( s, buf, size, 0 );
265    if( ret < 0 )
266    {
267        if( errno == EAGAIN || errno == EWOULDBLOCK )
268        {
269            ret = TR_NET_BLOCK;
270        }
271        else
272        {
273            ret = TR_NET_CLOSE;
274        }
275    }
276    if( !ret )
277    {
278        ret = TR_NET_CLOSE;
279    }
280
281    return ret;
282}
283
284void tr_netClose( int s )
285{
286#ifdef BEOS_NETSERVER
287    closesocket( s );
288#else
289    close( s );
290#endif
291}
Note: See TracBrowser for help on using the repository browser.