~ubuntu-branches/ubuntu/maverick/transmission/maverick

« back to all changes in this revision

Viewing changes to libtransmission/net.c

  • Committer: Bazaar Package Importer
  • Author(s): Philipp Benner
  • Date: 2006-08-29 20:50:41 UTC
  • Revision ID: james.westby@ubuntu.com-20060829205041-mzhpiqksdf7pbk17
Tags: upstream-0.6.1.dfsg
ImportĀ upstreamĀ versionĀ 0.6.1.dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/******************************************************************************
 
2
 * $Id: net.c 261 2006-05-29 21:27:31Z titer $
 
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 "transmission.h"
 
26
 
 
27
/***********************************************************************
 
28
 * DNS resolution
 
29
 **********************************************************************/
 
30
 
 
31
/***********************************************************************
 
32
 * tr_netResolve
 
33
 ***********************************************************************
 
34
 * Synchronous "resolution": only works with character strings
 
35
 * representing numbers expressed in the Internet standard `.' notation.
 
36
 * Returns a non-zero value if an error occurs.
 
37
 **********************************************************************/
 
38
int tr_netResolve( char * address, struct in_addr * addr )
 
39
{
 
40
    addr->s_addr = inet_addr( address );
 
41
    return ( addr->s_addr == 0xFFFFFFFF );
 
42
}
 
43
 
 
44
/* TODO: Make this code reentrant */
 
45
static tr_thread_t  resolveThread;
 
46
static tr_lock_t    resolveLock;
 
47
static volatile int resolveDie;
 
48
static tr_resolve_t * resolveQueue;
 
49
 
 
50
static void resolveRelease ( tr_resolve_t * );
 
51
static void resolveFunc    ( void * );
 
52
 
 
53
struct tr_resolve_s
 
54
{
 
55
    int            status;
 
56
    char           * address;
 
57
    struct in_addr addr;
 
58
 
 
59
    int            refcount;
 
60
    tr_resolve_t   * next;
 
61
};
 
62
 
 
63
/***********************************************************************
 
64
 * tr_netResolveThreadInit
 
65
 ***********************************************************************
 
66
 * Initializes the static variables used for resolution and launch the
 
67
 * gethostbyname thread.
 
68
 **********************************************************************/
 
69
void tr_netResolveThreadInit()
 
70
{
 
71
    resolveDie   = 0;
 
72
    resolveQueue = NULL;
 
73
    tr_lockInit( &resolveLock );
 
74
    tr_threadCreate( &resolveThread, resolveFunc, NULL );
 
75
}
 
76
 
 
77
/***********************************************************************
 
78
 * tr_netResolveThreadClose
 
79
 ***********************************************************************
 
80
 * Notices the gethostbyname thread that is should terminate. Doesn't
 
81
 * wait until it does, in case it is stuck in a resolution: we let it
 
82
 * die and clean itself up.
 
83
 **********************************************************************/
 
84
void tr_netResolveThreadClose()
 
85
{
 
86
    tr_lockLock( &resolveLock );
 
87
    resolveDie = 1;
 
88
    tr_lockUnlock( &resolveLock );
 
89
    tr_wait( 200 );
 
90
}
 
91
 
 
92
/***********************************************************************
 
93
 * tr_netResolveInit
 
94
 ***********************************************************************
 
95
 * Adds an address to the resolution queue.
 
96
 **********************************************************************/
 
97
tr_resolve_t * tr_netResolveInit( char * address )
 
98
{
 
99
    tr_resolve_t * r;
 
100
 
 
101
    r           = malloc( sizeof( tr_resolve_t ) );
 
102
    r->status   = TR_RESOLVE_WAIT;
 
103
    r->address  = strdup( address );
 
104
    r->refcount = 2;
 
105
    r->next     = NULL;
 
106
 
 
107
    tr_lockLock( &resolveLock );
 
108
    if( !resolveQueue )
 
109
    {
 
110
        resolveQueue = r;
 
111
    }
 
112
    else
 
113
    {
 
114
        tr_resolve_t * iter;
 
115
        for( iter = resolveQueue; iter->next; iter = iter->next );
 
116
        iter->next = r;
 
117
    }
 
118
    tr_lockUnlock( &resolveLock );
 
119
 
 
120
    return r;
 
121
}
 
122
 
 
123
/***********************************************************************
 
124
 * tr_netResolvePulse
 
125
 ***********************************************************************
 
126
 * Checks the current status of a resolution.
 
127
 **********************************************************************/
 
128
int tr_netResolvePulse( tr_resolve_t * r, struct in_addr * addr )
 
129
{
 
130
    int ret;
 
131
 
 
132
    tr_lockLock( &resolveLock );
 
133
    ret = r->status;
 
134
    if( ret == TR_RESOLVE_OK )
 
135
    {
 
136
        *addr = r->addr;
 
137
    }
 
138
    tr_lockUnlock( &resolveLock );
 
139
 
 
140
    return ret;
 
141
}
 
142
 
 
143
/***********************************************************************
 
144
 * tr_netResolveClose
 
145
 ***********************************************************************
 
146
 * 
 
147
 **********************************************************************/
 
148
void tr_netResolveClose( tr_resolve_t * r )
 
149
{
 
150
    resolveRelease( r );
 
151
}
 
152
 
 
153
/***********************************************************************
 
154
 * resolveRelease
 
155
 ***********************************************************************
 
156
 * The allocated tr_resolve_t structures should be freed when
 
157
 * tr_netResolveClose was called *and* it was removed from the queue.
 
158
 * This can happen in any order, so we use a refcount to know we can
 
159
 * take it out.
 
160
 **********************************************************************/
 
161
static void resolveRelease( tr_resolve_t * r )
 
162
{
 
163
    if( --r->refcount < 1 )
 
164
    {
 
165
        free( r->address );
 
166
        free( r );
 
167
    }
 
168
}
 
169
 
 
170
/***********************************************************************
 
171
 * resolveFunc
 
172
 ***********************************************************************
 
173
 * Keeps waiting for addresses to resolve, and removes them from the
 
174
 * queue once resolution is done.
 
175
 **********************************************************************/
 
176
static void resolveFunc( void * arg UNUSED )
 
177
{
 
178
    tr_resolve_t * r;
 
179
    struct hostent * host;
 
180
 
 
181
    tr_dbg( "Resolve thread started" );
 
182
 
 
183
    tr_lockLock( &resolveLock );
 
184
 
 
185
    while( !resolveDie )
 
186
    {
 
187
        if( !( r = resolveQueue ) )
 
188
        {
 
189
            /* TODO: Use a condition wait */
 
190
            tr_lockUnlock( &resolveLock );
 
191
            tr_wait( 50 );
 
192
            tr_lockLock( &resolveLock );
 
193
            continue;
 
194
        }
 
195
 
 
196
        /* Blocking resolution */
 
197
        tr_lockUnlock( &resolveLock );
 
198
        host = gethostbyname( r->address );
 
199
        tr_lockLock( &resolveLock );
 
200
 
 
201
        if( host )
 
202
        {
 
203
            memcpy( &r->addr, host->h_addr, host->h_length );
 
204
            r->status = TR_RESOLVE_OK;
 
205
        }
 
206
        else
 
207
        {
 
208
            r->status = TR_RESOLVE_ERROR;
 
209
        }
 
210
        
 
211
        resolveQueue = r->next;
 
212
        resolveRelease( r );
 
213
    }
 
214
 
 
215
    /* Clean up  */
 
216
    tr_lockUnlock( &resolveLock );
 
217
    tr_lockClose( &resolveLock );
 
218
    while( ( r = resolveQueue ) )
 
219
    {
 
220
        resolveQueue = r->next;
 
221
        resolveRelease( r );
 
222
    }
 
223
 
 
224
    tr_dbg( "Resolve thread exited" );
 
225
}
 
226
 
 
227
 
 
228
/***********************************************************************
 
229
 * TCP sockets
 
230
 **********************************************************************/
 
231
 
 
232
static int makeSocketNonBlocking( int s )
 
233
{
 
234
    int flags;
 
235
 
 
236
#ifdef SYS_BEOS
 
237
    flags = 1;
 
238
    if( setsockopt( s, SOL_SOCKET, SO_NONBLOCK,
 
239
                    &flags, sizeof( int ) ) < 0 )
 
240
#else
 
241
    if( ( flags = fcntl( s, F_GETFL, 0 ) ) < 0 ||
 
242
        fcntl( s, F_SETFL, flags | O_NONBLOCK ) < 0 )
 
243
#endif
 
244
    {
 
245
        tr_err( "Could not set socket to non-blocking mode (%s)",
 
246
                strerror( errno ) );
 
247
        tr_netClose( s );
 
248
        return -1;
 
249
    }
 
250
 
 
251
    return s;
 
252
}
 
253
 
 
254
static int createSocket()
 
255
{
 
256
    int s;
 
257
 
 
258
    s = socket( AF_INET, SOCK_STREAM, 0 );
 
259
    if( s < 0 )
 
260
    {
 
261
        tr_err( "Could not create socket (%s)", strerror( errno ) );
 
262
        return -1;
 
263
    }
 
264
 
 
265
    return makeSocketNonBlocking( s );
 
266
}
 
267
 
 
268
int tr_netOpen( struct in_addr addr, in_port_t port )
 
269
{
 
270
    int s;
 
271
    struct sockaddr_in sock;
 
272
 
 
273
    s = createSocket();
 
274
    if( s < 0 )
 
275
    {
 
276
        return -1;
 
277
    }
 
278
 
 
279
    memset( &sock, 0, sizeof( sock ) );
 
280
    sock.sin_family      = AF_INET;
 
281
    sock.sin_addr.s_addr = addr.s_addr;
 
282
    sock.sin_port        = port;
 
283
 
 
284
    if( connect( s, (struct sockaddr *) &sock,
 
285
                 sizeof( struct sockaddr_in ) ) < 0 &&
 
286
        errno != EINPROGRESS )
 
287
    {
 
288
        tr_err( "Could not connect socket (%s)", strerror( errno ) );
 
289
        tr_netClose( s );
 
290
        return -1;
 
291
    }
 
292
 
 
293
    return s;
 
294
}
 
295
 
 
296
int tr_netBind( int port )
 
297
{
 
298
    int s;
 
299
    struct sockaddr_in sock;
 
300
#ifdef SO_REUSEADDR
 
301
    int optval;
 
302
#endif
 
303
 
 
304
    s = createSocket();
 
305
    if( s < 0 )
 
306
    {
 
307
        return -1;
 
308
    }
 
309
 
 
310
#ifdef SO_REUSEADDR
 
311
    optval = 1;
 
312
    setsockopt( s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof( optval ) );
 
313
#endif
 
314
 
 
315
    memset( &sock, 0, sizeof( sock ) );
 
316
    sock.sin_family      = AF_INET;
 
317
    sock.sin_addr.s_addr = INADDR_ANY;
 
318
    sock.sin_port        = htons( port );
 
319
 
 
320
    if( bind( s, (struct sockaddr *) &sock,
 
321
               sizeof( struct sockaddr_in ) ) )
 
322
    {
 
323
        tr_err( "Could not bind port %d", port );
 
324
        tr_netClose( s );
 
325
        return -1;
 
326
    }
 
327
   
 
328
    tr_inf( "Binded port %d", port );
 
329
    listen( s, 5 );
 
330
 
 
331
    return s;
 
332
}
 
333
 
 
334
int tr_netAccept( int s, struct in_addr * addr, in_port_t * port )
 
335
{
 
336
    int t;
 
337
    unsigned len;
 
338
    struct sockaddr_in sock;
 
339
 
 
340
    len = sizeof( sock );
 
341
    t   = accept( s, (struct sockaddr *) &sock, &len );
 
342
 
 
343
    if( t < 0 )
 
344
    {
 
345
        return -1;
 
346
    }
 
347
    
 
348
    *addr = sock.sin_addr;
 
349
    *port = sock.sin_port;
 
350
 
 
351
    return makeSocketNonBlocking( t );
 
352
}
 
353
 
 
354
int tr_netSend( int s, uint8_t * buf, int size )
 
355
{
 
356
    int ret;
 
357
 
 
358
    ret = send( s, buf, size, 0 );
 
359
    if( ret < 0 )
 
360
    {
 
361
        if( errno == ENOTCONN || errno == EAGAIN || errno == EWOULDBLOCK )
 
362
        {
 
363
            ret = TR_NET_BLOCK;
 
364
        }
 
365
        else
 
366
        {
 
367
            ret = TR_NET_CLOSE;
 
368
        }
 
369
    }
 
370
 
 
371
    return ret;
 
372
}
 
373
 
 
374
int tr_netRecv( int s, uint8_t * buf, int size )
 
375
{
 
376
    int ret;
 
377
 
 
378
    ret = recv( s, buf, size, 0 );
 
379
    if( ret < 0 )
 
380
    {
 
381
        if( errno == EAGAIN || errno == EWOULDBLOCK )
 
382
        {
 
383
            ret = TR_NET_BLOCK;
 
384
        }
 
385
        else
 
386
        {
 
387
            ret = TR_NET_CLOSE;
 
388
        }
 
389
    }
 
390
    if( !ret )
 
391
    {
 
392
        ret = TR_NET_CLOSE;
 
393
    }
 
394
 
 
395
    return ret;
 
396
}
 
397
 
 
398
void tr_netClose( int s )
 
399
{
 
400
#ifdef BEOS_NETSERVER
 
401
    closesocket( s );
 
402
#else
 
403
    close( s );
 
404
#endif
 
405
}