~ubuntu-branches/ubuntu/jaunty/transmission/jaunty-security

« back to all changes in this revision

Viewing changes to libtransmission/trevent.c

  • Committer: Bazaar Package Importer
  • Author(s): Chris Coulson
  • Date: 2008-11-28 15:33:48 UTC
  • mfrom: (1.1.19 upstream)
  • Revision ID: james.westby@ubuntu.com-20081128153348-it70trfnxiroblmc
Tags: 1.40-0ubuntu1
* New upstream release (LP: #302672)
  - Tracker communication uses fewer resources
  - More accurate bandwidth limits
  - Reduce disk fragmentation by preallocating files (LP: #287726)
  - Stability, security and performance improvements to the RPC /
    Web UI server (closes LP: #290423)
  - Support compression when serving Web UI and RPC responses
  - Simplify the RPC whitelist
  - Fix bug that prevented handshakes with encrypted BitComet peers
  - Fix 1.3x bug that could re-download some data unnecessarily
    (LP: #295040)
  - Option to automatically update the blocklist weekly
  - Added off-hour bandwidth scheduling
  - Simplify file/priority selection in the details dialog
  - Fix a couple of crashes
  - New / updated translations
  - Don't inhibit hibernation by default (LP: #292929)
  - Use "close" animation when sending to notification area (LP: #130811)
  - Fix resize problems (LP: #269872)
  - Support "--version" option when launching from command line
    (LP: #292011)
  - Correctly parse announce URLs that have leading or trailing
    spaces (LP: #262411)
  - Display an error when "Open Torrent" fails (LP: #281463)
* Dropped 10_fix_crasher_from_upstream.dpatch: Fix is in this
  upstream release.
* debian/control: Don't just build-depend on libcurl-dev, which is
  a virtual package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
3
3
 *
4
4
 * This file is licensed by the GPL version 2.  Works owned by the
5
5
 * Transmission project are granted a special exemption to clause 2(b)
6
 
 * so that the bulk of its code can remain under the MIT license. 
 
6
 * so that the bulk of its code can remain under the MIT license.
7
7
 * This exemption does not extend to derived works not owned by
8
8
 * the Transmission project.
9
9
 *
10
 
 * $Id: trevent.c 6253 2008-06-25 11:34:35Z charles $
 
10
 * $Id: trevent.c 6961 2008-10-26 15:39:04Z charles $
11
11
 */
12
12
 
13
13
#include <assert.h>
19
19
#include <signal.h>
20
20
 
21
21
#ifdef WIN32
22
 
  #include <fcntl.h>
23
 
  #define pipe(f) _pipe(f, 1000, _O_BINARY)
 
22
 
 
23
#include <WinSock2.h> 
 
24
 
 
25
static int 
 
26
pgpipe( int handles[2] ) 
 
27
{
 
28
        SOCKET s;
 
29
        struct sockaddr_in serv_addr;
 
30
        int len = sizeof( serv_addr );
 
31
 
 
32
        handles[0] = handles[1] = INVALID_SOCKET;
 
33
 
 
34
        if ( ( s = socket( AF_INET, SOCK_STREAM, 0 ) ) == INVALID_SOCKET )
 
35
        {
 
36
/*              ereport(LOG, (errmsg_internal("pgpipe failed to create socket: %ui", WSAGetLastError()))); */
 
37
                return -1;
 
38
        }
 
39
 
 
40
        memset( &serv_addr, 0, sizeof( serv_addr ) );
 
41
        serv_addr.sin_family = AF_INET;
 
42
        serv_addr.sin_port = htons(0);
 
43
        serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
 
44
        if (bind(s, (SOCKADDR *) & serv_addr, len) == SOCKET_ERROR)
 
45
        {
 
46
/*              ereport(LOG, (errmsg_internal("pgpipe failed to bind: %ui", WSAGetLastError()))); */
 
47
                closesocket(s);
 
48
                return -1;
 
49
        }
 
50
        if (listen(s, 1) == SOCKET_ERROR)
 
51
        {
 
52
/*              ereport(LOG, (errmsg_internal("pgpipe failed to listen: %ui", WSAGetLastError()))); */
 
53
                closesocket(s);
 
54
                return -1;
 
55
        }
 
56
        if (getsockname(s, (SOCKADDR *) & serv_addr, &len) == SOCKET_ERROR)
 
57
        {
 
58
/*              ereport(LOG, (errmsg_internal("pgpipe failed to getsockname: %ui", WSAGetLastError()))); */
 
59
                closesocket(s);
 
60
                return -1;
 
61
        }
 
62
        if ((handles[1] = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
 
63
        {
 
64
/*              ereport(LOG, (errmsg_internal("pgpipe failed to create socket 2: %ui", WSAGetLastError()))); */
 
65
                closesocket(s);
 
66
                return -1;
 
67
        }
 
68
 
 
69
        if (connect(handles[1], (SOCKADDR *) & serv_addr, len) == SOCKET_ERROR)
 
70
        {
 
71
/*              ereport(LOG, (errmsg_internal("pgpipe failed to connect socket: %ui", WSAGetLastError()))); */
 
72
                closesocket(s);
 
73
                return -1;
 
74
        }
 
75
        if ((handles[0] = accept(s, (SOCKADDR *) & serv_addr, &len)) == INVALID_SOCKET)
 
76
        {
 
77
/*              ereport(LOG, (errmsg_internal("pgpipe failed to accept socket: %ui", WSAGetLastError()))); */
 
78
                closesocket(handles[1]);
 
79
                handles[1] = INVALID_SOCKET;
 
80
                closesocket(s);
 
81
                return -1;
 
82
        }
 
83
        closesocket(s);
 
84
        return 0;
 
85
}
 
86
 
 
87
static int 
 
88
piperead( int s, char *buf, int len ) 
 
89
 
90
        int ret = recv(s, buf, len, 0); 
 
91
 
 
92
        if (ret < 0 && WSAGetLastError() == WSAECONNRESET) 
 
93
                /* EOF on the pipe! (win32 socket based implementation) */ 
 
94
                ret = 0; 
 
95
        return ret; 
 
96
 
97
 
 
98
#define pipe(a) pgpipe(a) 
 
99
#define pipewrite(a,b,c) send(a,(char*)b,c,0) 
 
100
 
24
101
#else
25
 
  #include <unistd.h>
 
102
#define piperead(a,b,c) read(a,b,c) 
 
103
#define pipewrite(a,b,c) write(a,b,c) 
26
104
#endif
27
105
 
 
106
#include <unistd.h> 
 
107
 
28
108
#include <event.h>
29
109
 
30
110
#include "transmission.h"
38
118
 
39
119
typedef struct tr_event_handle
40
120
{
41
 
    uint8_t die;
42
 
    int fds[2];
43
 
    tr_lock * lock;
44
 
    tr_handle * h;
45
 
    tr_thread * thread;
 
121
    uint8_t      die;
 
122
    int          fds[2];
 
123
    tr_lock *    lock;
 
124
    tr_handle *  h;
 
125
    tr_thread *  thread;
46
126
    struct event_base * base;
47
127
    struct event pipeEvent;
48
128
}
49
129
tr_event_handle;
50
130
 
51
 
typedef int timer_func(void*);
 
131
typedef int timer_func ( void* );
52
132
 
53
133
struct tr_timer
54
134
{
55
 
    struct event event;
56
 
    struct timeval tv;
57
 
    timer_func * func;
58
 
    void * user_data;
59
 
    struct tr_event_handle * eh;
60
 
    uint8_t inCallback;
 
135
    unsigned int              inCallback : 1;
 
136
    timer_func *              func;
 
137
    void *                    user_data;
 
138
    struct tr_event_handle *  eh;
 
139
    struct timeval            tv;
 
140
    struct event              event;
61
141
};
62
142
 
63
143
struct tr_run_data
64
144
{
65
 
    void (*func)( void * );
66
 
    void * user_data;
 
145
    void    ( *func )( void * );
 
146
    void *  user_data;
67
147
};
68
148
 
69
 
#define dbgmsg(fmt...) tr_deepLog( __FILE__, __LINE__, "event", ##fmt )
 
149
#define dbgmsg( ... ) \
 
150
    do { \
 
151
        if( tr_deepLoggingIsActive( ) ) \
 
152
            tr_deepLog( __FILE__, __LINE__, "event", __VA_ARGS__ ); \
 
153
    } while( 0 )
70
154
 
71
155
static void
72
 
readFromPipe( int fd, short eventType, void * veh )
 
156
readFromPipe( int    fd,
 
157
              short  eventType,
 
158
              void * veh )
73
159
{
74
 
    char ch;
75
 
    int ret;
 
160
    char              ch;
 
161
    int               ret;
76
162
    tr_event_handle * eh = veh;
 
163
 
77
164
    dbgmsg( "readFromPipe: eventType is %hd", eventType );
78
165
 
79
166
    /* read the command type */
80
167
    ch = '\0';
81
 
    do {
82
 
        ret = read( fd, &ch, 1 );
83
 
    } while( !eh->die && ret<0 && errno==EAGAIN );
 
168
    do
 
169
    {
 
170
        ret = piperead( fd, &ch, 1 );
 
171
    }
 
172
    while( !eh->die && ret < 0 && errno == EAGAIN );
 
173
 
84
174
    dbgmsg( "command is [%c], ret is %d, errno is %d", ch, ret, (int)errno );
85
175
 
86
176
    switch( ch )
88
178
        case 'r': /* run in libevent thread */
89
179
        {
90
180
            struct tr_run_data data;
91
 
            const size_t nwant = sizeof( data );
92
 
            const ssize_t ngot = read( fd, &data, nwant );
93
 
            if( !eh->die && ( ngot == (ssize_t)nwant ) ) {
 
181
            const size_t       nwant = sizeof( data );
 
182
            const ssize_t      ngot = piperead( fd, &data, nwant );
 
183
            if( !eh->die && ( ngot == (ssize_t)nwant ) )
 
184
            {
94
185
                dbgmsg( "invoking function in libevent thread" );
95
 
                (data.func)( data.user_data );
 
186
                ( data.func )( data.user_data );
96
187
            }
97
188
            break;
98
189
        }
 
190
 
99
191
        case 't': /* create timer */
100
192
        {
101
 
            tr_timer * timer;
102
 
            const size_t nwant = sizeof( timer );
103
 
            const ssize_t ngot = read( fd, &timer, nwant );
104
 
            if( !eh->die && ( ngot == (ssize_t)nwant ) ) {
 
193
            tr_timer *    timer;
 
194
            const size_t  nwant = sizeof( timer );
 
195
            const ssize_t ngot = piperead( fd, &timer, nwant );
 
196
            if( !eh->die && ( ngot == (ssize_t)nwant ) )
 
197
            {
105
198
                dbgmsg( "adding timer in libevent thread" );
106
199
                evtimer_add( &timer->event, &timer->tv );
107
200
            }
108
201
            break;
109
202
        }
 
203
 
110
204
        case '\0': /* eof */
111
205
        {
112
206
            dbgmsg( "pipe eof reached... removing event listener" );
113
207
            event_del( &eh->pipeEvent );
114
208
            break;
115
209
        }
 
210
 
116
211
        default:
117
212
        {
118
213
            assert( 0 && "unhandled command type!" );
122
217
}
123
218
 
124
219
static void
125
 
logFunc( int severity, const char * message )
 
220
logFunc( int          severity,
 
221
         const char * message )
126
222
{
127
223
    if( severity >= _EVENT_LOG_ERR )
128
 
        tr_nerr( "%s", message );
 
224
        tr_err( "%s", message );
129
225
    else
130
 
        tr_ndbg( "%s", message );
 
226
        tr_dbg( "%s", message );
131
227
}
132
228
 
133
229
static void
134
230
libeventThreadFunc( void * veh )
135
231
{
136
 
    tr_event_handle * eh = (tr_event_handle *) veh;
 
232
    tr_event_handle * eh = veh;
 
233
 
137
234
    tr_dbg( "Starting libevent thread" );
138
235
 
139
236
#ifndef WIN32
141
238
    signal( SIGPIPE, SIG_IGN );
142
239
#endif
143
240
 
144
 
    eh->base = event_init( );
145
241
    eh->h->events = eh;
146
 
    event_set_log_callback( logFunc );
147
242
 
148
243
    /* listen to the pipe's read fd */
149
 
    event_set( &eh->pipeEvent, eh->fds[0], EV_READ|EV_PERSIST, readFromPipe, veh );
 
244
    event_set( &eh->pipeEvent, eh->fds[0], EV_READ | EV_PERSIST,
 
245
               readFromPipe,
 
246
               veh );
150
247
    event_add( &eh->pipeEvent, NULL );
151
 
 
 
248
    event_set_log_callback( logFunc );
152
249
    event_dispatch( );
153
250
 
154
251
    tr_lockFree( eh->lock );
167
264
    eh->lock = tr_lockNew( );
168
265
    pipe( eh->fds );
169
266
    eh->h = handle;
170
 
    eh->thread = tr_threadNew( libeventThreadFunc, eh, "libeventThreadFunc" );
 
267
    eh->base = event_init( );
 
268
    eh->thread = tr_threadNew( libeventThreadFunc, eh );
171
269
}
172
270
 
173
271
void
175
273
{
176
274
    handle->events->die = TRUE;
177
275
    tr_deepLog( __FILE__, __LINE__, NULL, "closing trevent pipe" );
178
 
    close( handle->events->fds[1] );
 
276
    EVUTIL_CLOSESOCKET( handle->events->fds[1] );
179
277
}
180
278
 
181
279
/**
185
283
int
186
284
tr_amInEventThread( struct tr_handle * handle )
187
285
{
 
286
    assert( handle );
 
287
    assert( handle->events );
 
288
 
188
289
    return tr_amInThread( handle->events->thread );
189
290
}
190
291
 
193
294
**/
194
295
 
195
296
static void
196
 
timerCallback( int fd UNUSED, short event UNUSED, void * vtimer )
 
297
timerCallback( int fd      UNUSED,
 
298
               short event UNUSED,
 
299
               void *      vtimer )
197
300
{
198
 
    int more;
 
301
    int               more;
199
302
    struct tr_timer * timer = vtimer;
200
303
 
201
304
    timer->inCallback = 1;
202
 
    more = (*timer->func)( timer->user_data );
 
305
    more = ( *timer->func )( timer->user_data );
203
306
    timer->inCallback = 0;
204
307
 
205
308
    if( more )
230
333
tr_timer*
231
334
tr_timerNew( struct tr_handle * handle,
232
335
             timer_func         func,
233
 
             void             * user_data,
 
336
             void *             user_data,
234
337
             uint64_t           interval_milliseconds )
235
338
{
236
 
    tr_timer * timer = tr_new0( tr_timer, 1 );
237
 
    timer->tv = tr_timevalMsec( interval_milliseconds );
 
339
    tr_timer * timer;
 
340
 
 
341
    assert( handle );
 
342
    assert( handle->events );
 
343
 
 
344
    timer = tr_new0( tr_timer, 1 );
 
345
    tr_timevalMsec( interval_milliseconds, &timer->tv );
238
346
    timer->func = func;
239
347
    timer->user_data = user_data;
240
348
    timer->eh = handle->events;
247
355
    else
248
356
    {
249
357
        const char ch = 't';
250
 
        int fd = handle->events->fds[1];
251
 
        tr_lock * lock = handle->events->lock;
 
358
        int        fd = handle->events->fds[1];
 
359
        tr_lock *  lock = handle->events->lock;
252
360
 
253
361
        tr_lockLock( lock );
254
 
        write( fd, &ch, 1 );
255
 
        write( fd, &timer, sizeof(timer) );
 
362
        pipewrite( fd, &ch, 1 );
 
363
        pipewrite( fd, &timer, sizeof( timer ) );
256
364
        tr_lockUnlock( lock );
257
365
    }
258
366
 
260
368
}
261
369
 
262
370
void
263
 
tr_runInEventThread( struct tr_handle * handle,
 
371
tr_runInEventThread( struct tr_handle *       handle,
264
372
                     void               func( void* ),
265
 
                     void             * user_data )
 
373
                     void *                   user_data )
266
374
{
 
375
    assert( handle );
 
376
    assert( handle->events );
 
377
 
267
378
    if( tr_amInThread( handle->events->thread ) )
268
379
    {
269
380
        (func)( user_data );
270
381
    }
271
382
    else
272
383
    {
273
 
        const char ch = 'r';
274
 
        int fd = handle->events->fds[1];
275
 
        tr_lock * lock = handle->events->lock;
 
384
        const char         ch = 'r';
 
385
        int                fd = handle->events->fds[1];
 
386
        tr_lock *          lock = handle->events->lock;
276
387
        struct tr_run_data data;
277
388
 
278
389
        tr_lockLock( lock );
279
 
        write( fd, &ch, 1 );
 
390
        pipewrite( fd, &ch, 1 );
280
391
        data.func = func;
281
392
        data.user_data = user_data;
282
 
        write( fd, &data, sizeof(data) );
 
393
        pipewrite( fd, &data, sizeof( data ) );
283
394
        tr_lockUnlock( lock );
284
395
    }
285
396
}
 
397
 
 
398
struct event_base *
 
399
tr_eventGetBase( tr_session * session )
 
400
{
 
401
    return session->events->base;
 
402
}