source: trunk/libtransmission/net.c @ 236

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

Code cleanup

File size: 6.7 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    addr->s_addr = inet_addr( address );
170    return ( addr->s_addr == 0xFFFFFFFF );
171}
172
173int tr_netOpen( struct in_addr addr, in_port_t port )
174{
175    int s;
176    struct sockaddr_in sock;
177
178    s = createSocket();
179    if( s < 0 )
180    {
181        return -1;
182    }
183
184    memset( &sock, 0, sizeof( sock ) );
185    sock.sin_family      = AF_INET;
186    sock.sin_addr.s_addr = addr.s_addr;
187    sock.sin_port        = port;
188
189    if( connect( s, (struct sockaddr *) &sock,
190                 sizeof( struct sockaddr_in ) ) < 0 &&
191        errno != EINPROGRESS )
192    {
193        tr_err( "Could not connect socket (%s)", strerror( errno ) );
194        tr_netClose( s );
195        return -1;
196    }
197
198    return s;
199}
200
201int tr_netBind( int port )
202{
203    int s;
204    struct sockaddr_in sock;
205#ifdef SO_REUSEADDR
206    int optval;
207#endif
208
209    s = createSocket();
210    if( s < 0 )
211    {
212        return -1;
213    }
214
215#ifdef SO_REUSEADDR
216    optval = 1;
217    setsockopt( s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof( optval ) );
218#endif
219
220    memset( &sock, 0, sizeof( sock ) );
221    sock.sin_family      = AF_INET;
222    sock.sin_addr.s_addr = INADDR_ANY;
223    sock.sin_port        = htons( port );
224
225    if( bind( s, (struct sockaddr *) &sock,
226               sizeof( struct sockaddr_in ) ) )
227    {
228        tr_err( "Could not bind port %d", port );
229        tr_netClose( s );
230        return -1;
231    }
232   
233    tr_inf( "Binded port %d", port );
234    listen( s, 5 );
235
236    return s;
237}
238
239int tr_netAccept( int s, struct in_addr * addr, in_port_t * port )
240{
241    int t;
242    unsigned len;
243    struct sockaddr_in sock;
244
245    len = sizeof( sock );
246    t   = accept( s, (struct sockaddr *) &sock, &len );
247
248    if( t < 0 )
249    {
250        return -1;
251    }
252   
253    *addr = sock.sin_addr;
254    *port = sock.sin_port;
255
256    return makeSocketNonBlocking( t );
257}
258
259int tr_netSend( int s, uint8_t * buf, int size )
260{
261    int ret;
262
263    ret = send( s, buf, size, 0 );
264    if( ret < 0 )
265    {
266        if( errno == ENOTCONN || errno == EAGAIN || errno == EWOULDBLOCK )
267        {
268            ret = TR_NET_BLOCK;
269        }
270        else
271        {
272            ret = TR_NET_CLOSE;
273        }
274    }
275
276    return ret;
277}
278
279int tr_netRecv( int s, uint8_t * buf, int size )
280{
281    int ret;
282
283    ret = recv( s, buf, size, 0 );
284    if( ret < 0 )
285    {
286        if( errno == EAGAIN || errno == EWOULDBLOCK )
287        {
288            ret = TR_NET_BLOCK;
289        }
290        else
291        {
292            ret = TR_NET_CLOSE;
293        }
294    }
295    if( !ret )
296    {
297        ret = TR_NET_CLOSE;
298    }
299
300    return ret;
301}
302
303void tr_netClose( int s )
304{
305#ifdef BEOS_NETSERVER
306    closesocket( s );
307#else
308    close( s );
309#endif
310}
Note: See TracBrowser for help on using the repository browser.