~ubuntu-branches/ubuntu/precise/transmission/precise

« back to all changes in this revision

Viewing changes to daemon/server.c

  • Committer: Bazaar Package Importer
  • Author(s): Leo Costela
  • Date: 2009-05-17 19:39:51 UTC
  • mto: (1.3.4 upstream) (2.2.1 squeeze)
  • mto: This revision was merged to the branch mainline in revision 36.
  • Revision ID: james.westby@ubuntu.com-20090517193951-k8x15sqoxzf7cuyx
ImportĀ upstreamĀ versionĀ 1.61

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/******************************************************************************
2
 
 * $Id: server.c 5766 2008-05-07 11:57:23Z charles $
3
 
 *
4
 
 * Copyright (c) 2007 Joshua Elsasser
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 <sys/types.h>
26
 
#include <sys/socket.h>
27
 
#include <sys/time.h>
28
 
#include <sys/un.h>
29
 
#include <assert.h>
30
 
#include <errno.h>
31
 
#include <event.h>
32
 
#include <fcntl.h>
33
 
#include <limits.h>
34
 
#include <stdio.h>
35
 
#include <stdlib.h>
36
 
#include <string.h>
37
 
#include <unistd.h>
38
 
 
39
 
#include <libtransmission/bencode.h>
40
 
#include <libtransmission/ipcparse.h>
41
 
#include <libtransmission/utils.h> /* tr_free */
42
 
 
43
 
#include "bsdtree.h"
44
 
#include "errors.h"
45
 
#include "misc.h"
46
 
#include "server.h"
47
 
#include "torrents.h"
48
 
 
49
 
/* time out clients after this many seconds */
50
 
#define CLIENT_TIMEOUT          ( 60 )
51
 
 
52
 
struct client
53
 
{
54
 
    int                  fd;
55
 
    struct bufferevent * ev;
56
 
    struct ipc_info    * ipc;
57
 
    RB_ENTRY( client )   link;
58
 
};
59
 
 
60
 
RB_HEAD( allclients, client );
61
 
 
62
 
static void newclient( int, short, void * );
63
 
static void noop     ( struct bufferevent *, void * );
64
 
static void byebye   ( struct bufferevent *, short, void * );
65
 
static void doread   ( struct bufferevent *, void * );
66
 
static int  queuemsg ( struct client *, uint8_t *, size_t );
67
 
static int  msgresp  ( struct client *, int64_t, enum ipc_msg );
68
 
static void defmsg   ( enum ipc_msg, benc_val_t *, int64_t, void * );
69
 
static void noopmsg  ( enum ipc_msg, benc_val_t *, int64_t, void * );
70
 
static void addmsg1  ( enum ipc_msg, benc_val_t *, int64_t, void * );
71
 
static void addmsg2  ( enum ipc_msg, benc_val_t *, int64_t, void * );
72
 
static void quitmsg  ( enum ipc_msg, benc_val_t *, int64_t, void * );
73
 
static void intmsg   ( enum ipc_msg, benc_val_t *, int64_t, void * );
74
 
static void strmsg   ( enum ipc_msg, benc_val_t *, int64_t, void * );
75
 
static void infomsg  ( enum ipc_msg, benc_val_t *, int64_t, void * );
76
 
static int  addinfo  ( benc_val_t *, int, int );
77
 
static int  addstat  ( benc_val_t *, int, int );
78
 
static void tormsg   ( enum ipc_msg, benc_val_t *, int64_t, void * );
79
 
static void lookmsg  ( enum ipc_msg, benc_val_t *, int64_t, void * );
80
 
static void prefmsg  ( enum ipc_msg, benc_val_t *, int64_t, void * );
81
 
static void supmsg   ( enum ipc_msg, benc_val_t *, int64_t, void * );
82
 
static int  clientcmp( struct client *, struct client * );
83
 
 
84
 
RB_GENERATE_STATIC( allclients, client, link, clientcmp )
85
 
INTCMP_FUNC( clientcmp, client, ev )
86
 
 
87
 
static struct event_base * gl_base    = NULL;
88
 
static struct ipc_funcs  * gl_tree    = NULL;
89
 
static int                 gl_debug   = 0;
90
 
static int                 gl_exiting = 0;
91
 
static struct allclients   gl_clients = RB_INITIALIZER( &gl_clients );
92
 
 
93
 
int
94
 
server_init( struct event_base * base )
95
 
{
96
 
    assert( NULL == gl_base && NULL == gl_tree );
97
 
    gl_base = base;
98
 
    gl_tree = ipc_initmsgs();
99
 
    if( NULL == gl_tree )
100
 
    {
101
 
        return -1;
102
 
    }
103
 
 
104
 
    ipc_addmsg( gl_tree, IPC_MSG_ADDMANYFILES, addmsg1 );
105
 
    ipc_addmsg( gl_tree, IPC_MSG_ADDONEFILE,   addmsg2 );
106
 
    ipc_addmsg( gl_tree, IPC_MSG_AUTOMAP,      intmsg  );
107
 
    ipc_addmsg( gl_tree, IPC_MSG_AUTOSTART,    intmsg  );
108
 
    ipc_addmsg( gl_tree, IPC_MSG_CRYPTO,       strmsg  );
109
 
    ipc_addmsg( gl_tree, IPC_MSG_DOWNLIMIT,    intmsg  );
110
 
    ipc_addmsg( gl_tree, IPC_MSG_DIR,          strmsg  );
111
 
    ipc_addmsg( gl_tree, IPC_MSG_GETAUTOMAP,   prefmsg );
112
 
    ipc_addmsg( gl_tree, IPC_MSG_GETAUTOSTART, prefmsg );
113
 
    ipc_addmsg( gl_tree, IPC_MSG_GETCRYPTO,    prefmsg );
114
 
    ipc_addmsg( gl_tree, IPC_MSG_GETDOWNLIMIT, prefmsg );
115
 
    ipc_addmsg( gl_tree, IPC_MSG_GETDIR,       prefmsg );
116
 
    ipc_addmsg( gl_tree, IPC_MSG_GETINFO,      infomsg );
117
 
    ipc_addmsg( gl_tree, IPC_MSG_GETINFOALL,   infomsg );
118
 
    ipc_addmsg( gl_tree, IPC_MSG_GETPEX,       prefmsg );
119
 
    ipc_addmsg( gl_tree, IPC_MSG_GETPORT,      prefmsg );
120
 
    ipc_addmsg( gl_tree, IPC_MSG_GETSTAT,      infomsg );
121
 
    ipc_addmsg( gl_tree, IPC_MSG_GETSTATALL,   infomsg );
122
 
    ipc_addmsg( gl_tree, IPC_MSG_GETUPLIMIT,   prefmsg );
123
 
    ipc_addmsg( gl_tree, IPC_MSG_GETSUP,       supmsg  );
124
 
    ipc_addmsg( gl_tree, IPC_MSG_LOOKUP,       lookmsg );
125
 
    ipc_addmsg( gl_tree, IPC_MSG_NOOP,         noopmsg );
126
 
    ipc_addmsg( gl_tree, IPC_MSG_PEX,          intmsg  );
127
 
    ipc_addmsg( gl_tree, IPC_MSG_PORT,         intmsg  );
128
 
    ipc_addmsg( gl_tree, IPC_MSG_QUIT,         quitmsg );
129
 
    ipc_addmsg( gl_tree, IPC_MSG_REMOVE,       tormsg  );
130
 
    ipc_addmsg( gl_tree, IPC_MSG_REMOVEALL,    tormsg  );
131
 
    ipc_addmsg( gl_tree, IPC_MSG_START,        tormsg  );
132
 
    ipc_addmsg( gl_tree, IPC_MSG_STARTALL,     tormsg  );
133
 
    ipc_addmsg( gl_tree, IPC_MSG_STOP,         tormsg  );
134
 
    ipc_addmsg( gl_tree, IPC_MSG_STOPALL,      tormsg  );
135
 
    ipc_addmsg( gl_tree, IPC_MSG_UPLIMIT,      intmsg  );
136
 
    ipc_addmsg( gl_tree, IPC_MSG_VERIFY,       tormsg  );
137
 
 
138
 
    ipc_setdefmsg( gl_tree, defmsg );
139
 
 
140
 
    return 0;
141
 
}
142
 
 
143
 
void
144
 
server_debug( int enable )
145
 
{
146
 
    gl_debug = enable;
147
 
}
148
 
 
149
 
int
150
 
server_listen( int fd )
151
 
{
152
 
    struct event * ev;
153
 
    int flags;
154
 
 
155
 
    assert( NULL != gl_base );
156
 
 
157
 
    flags = fcntl( fd, F_GETFL );
158
 
    if( 0 > flags )
159
 
    {
160
 
        errnomsg( "failed to get flags on socket" );
161
 
        return -1;
162
 
    }
163
 
    if( 0 > fcntl( fd, F_SETFL, flags | O_NONBLOCK ) )
164
 
    {
165
 
        errnomsg( "failed to set flags on socket" );
166
 
        return -1;
167
 
    }
168
 
 
169
 
    if( 0 > listen( fd, 5 ) )
170
 
    {
171
 
        errnomsg( "failed to listen on socket" );
172
 
        return -1;
173
 
    }
174
 
 
175
 
    ev = malloc( sizeof *ev );
176
 
    if( NULL == ev )
177
 
    {
178
 
        mallocmsg( sizeof *ev );
179
 
        return -1;
180
 
    }
181
 
 
182
 
    event_set( ev, fd, EV_READ | EV_PERSIST, newclient, ev );
183
 
    event_base_set( gl_base, ev );
184
 
    event_add( ev, NULL );
185
 
 
186
 
    return 0;
187
 
}
188
 
 
189
 
void
190
 
server_quit( void )
191
 
{
192
 
    struct client * ii, * next;
193
 
 
194
 
    if(gl_exiting)
195
 
        return;
196
 
 
197
 
    torrent_exit( 0 );
198
 
    gl_exiting = 1;
199
 
 
200
 
    for( ii = RB_MIN( allclients, &gl_clients ); NULL != ii; ii = next )
201
 
    {
202
 
        next = RB_NEXT( allclients, &gl_clients, ii );
203
 
        byebye( ii->ev, EVBUFFER_EOF, NULL );
204
 
    }
205
 
}
206
 
 
207
 
void
208
 
newclient( int fd, short event UNUSED, void * arg )
209
 
{
210
 
    struct sockaddr_un   sa;
211
 
    struct client      * client, * old;
212
 
    socklen_t            socklen;
213
 
    struct bufferevent * clev;
214
 
    int                  clfd;
215
 
    size_t               buflen;
216
 
    uint8_t            * buf;
217
 
 
218
 
    if( gl_exiting )
219
 
    {
220
 
        event_del( arg );
221
 
        return;
222
 
    }
223
 
 
224
 
    for( ;; )
225
 
    {
226
 
        client = calloc( 1, sizeof *client );
227
 
        if( NULL == client )
228
 
        {
229
 
            mallocmsg( sizeof *client );
230
 
            return;
231
 
        }
232
 
 
233
 
        socklen = sizeof sa;
234
 
        clfd = accept( fd, ( struct sockaddr * )&sa, &socklen );
235
 
        if( 0 > clfd )
236
 
        {
237
 
            if( EWOULDBLOCK != errno && EAGAIN != errno &&
238
 
                ECONNABORTED != errno )
239
 
            {
240
 
                errnomsg( "failed to accept ipc connection" );
241
 
            }
242
 
            free( client );
243
 
            break;
244
 
        }
245
 
 
246
 
        client->ipc = ipc_newcon( gl_tree );
247
 
        if( NULL == client->ipc )
248
 
        {
249
 
            close( clfd );
250
 
            free( client );
251
 
            return;
252
 
        }
253
 
 
254
 
        clev = bufferevent_new( clfd, doread, noop, byebye, client );
255
 
        if( NULL == clev )
256
 
        {
257
 
            errnomsg( "failed to create bufferevent" );
258
 
            close( clfd );
259
 
            ipc_freecon( client->ipc );
260
 
            free( client );
261
 
            return;
262
 
        }
263
 
        bufferevent_base_set( gl_base, clev );
264
 
        bufferevent_settimeout( clev, CLIENT_TIMEOUT, CLIENT_TIMEOUT );
265
 
 
266
 
        client->fd      = clfd;
267
 
        client->ev      = clev;
268
 
        old = RB_INSERT( allclients, &gl_clients, client );
269
 
        assert( NULL == old );
270
 
 
271
 
        if( gl_debug )
272
 
        {
273
 
            printf( "*** new client %i\n", clfd );
274
 
        }
275
 
 
276
 
        bufferevent_enable( clev, EV_READ );
277
 
        buf = ipc_mkvers( &buflen, "Transmission daemon " LONG_VERSION_STRING );
278
 
        if( 0 > queuemsg( client, buf, buflen ) )
279
 
        {
280
 
            free( buf );
281
 
            return;
282
 
        }
283
 
        free( buf );
284
 
    }
285
 
}
286
 
 
287
 
void
288
 
noop( struct bufferevent * ev UNUSED, void * arg UNUSED )
289
 
{
290
 
    /* libevent prior to 1.2 couldn't handle a NULL write callback */
291
 
}
292
 
 
293
 
void
294
 
byebye( struct bufferevent * ev, short what, void * arg UNUSED )
295
 
{
296
 
    struct client * client, key;
297
 
 
298
 
    if( !( EVBUFFER_EOF & what ) )
299
 
    {
300
 
        if( EVBUFFER_TIMEOUT & what )
301
 
        {
302
 
            errmsg( "client connection timed out" );
303
 
        }
304
 
        else if( EVBUFFER_READ & what )
305
 
        {
306
 
            errmsg( "read error on client connection" );
307
 
        }
308
 
        else if( EVBUFFER_WRITE & what )
309
 
        {
310
 
            errmsg( "write error on client connection" );
311
 
        }
312
 
        else if( EVBUFFER_ERROR & what )
313
 
        {
314
 
            errmsg( "error on client connection" );
315
 
        }
316
 
        else
317
 
        {
318
 
            errmsg( "unknown error on client connection: 0x%x", what );
319
 
        }
320
 
    }
321
 
 
322
 
    memset( &key, 0, sizeof key );
323
 
    key.ev = ev;
324
 
    client = RB_FIND( allclients, &gl_clients, &key );
325
 
    assert( NULL != client );
326
 
    RB_REMOVE( allclients, &gl_clients, client );
327
 
    bufferevent_free( ev );
328
 
    close( client->fd );
329
 
    ipc_freecon( client->ipc );
330
 
    if( gl_debug )
331
 
    {
332
 
        printf( "*** client %i went bye-bye\n", client->fd );
333
 
    }
334
 
    free( client );
335
 
}
336
 
 
337
 
void
338
 
doread( struct bufferevent * ev, void * arg )
339
 
{
340
 
    struct client * client = arg;
341
 
    ssize_t         res;
342
 
    uint8_t       * buf;
343
 
    size_t          len;
344
 
 
345
 
    assert( !gl_exiting );
346
 
 
347
 
    buf = EVBUFFER_DATA( EVBUFFER_INPUT( ev ) );
348
 
    len = EVBUFFER_LENGTH( EVBUFFER_INPUT( ev ) );
349
 
 
350
 
    if( gl_debug )
351
 
    {
352
 
        printf( "<<< %zu bytes from client %i: ", len, client->fd );
353
 
        fwrite( buf, 1, len, stdout );
354
 
        putc( '\n', stdout );
355
 
    }
356
 
 
357
 
    if( IPC_MIN_MSG_LEN > len )
358
 
    {
359
 
        return;
360
 
    }
361
 
 
362
 
    res = ipc_handleMessages( client->ipc, buf, len, client );
363
 
 
364
 
    if( gl_exiting )
365
 
    {
366
 
        return;
367
 
    }
368
 
 
369
 
    if( 0 > res )
370
 
    {
371
 
        switch( errno )
372
 
        {
373
 
            case EPERM:
374
 
                errmsg( "unsupported protocol version" );
375
 
                break;
376
 
            case EINVAL:
377
 
                errmsg( "protocol parse error" );
378
 
                break;
379
 
            default:
380
 
                errnomsg( "parsing failed" );
381
 
                break;
382
 
        }
383
 
        byebye( ev, EVBUFFER_ERROR, NULL );
384
 
    }
385
 
    else if( 0 < res )
386
 
    {
387
 
        evbuffer_drain( EVBUFFER_INPUT( ev ), res );
388
 
    }
389
 
}
390
 
 
391
 
static int
392
 
queuemsg( struct client * client, uint8_t * buf, size_t buflen )
393
 
{
394
 
    if( NULL == buf )
395
 
    {
396
 
        if( EPERM != errno )
397
 
        {
398
 
            errnomsg( "failed to build message" );
399
 
            byebye( client->ev, EVBUFFER_EOF, NULL );
400
 
        }
401
 
        return -1;
402
 
    }
403
 
 
404
 
    if( gl_debug )
405
 
    {
406
 
        printf( ">>> %zu bytes to client %i: ", buflen, client->fd );
407
 
        fwrite( buf, 1, buflen, stdout );
408
 
        putc( '\n', stdout );
409
 
    }
410
 
 
411
 
    if( 0 > bufferevent_write( client->ev, buf, buflen ) )
412
 
    {
413
 
        errnomsg( "failed to buffer %zd bytes of data for write", buflen );
414
 
        return -1;
415
 
    }
416
 
 
417
 
    return 0;
418
 
}
419
 
 
420
 
static int
421
 
queuepkmsg( struct client * client, tr_benc * pk )
422
 
{
423
 
    size_t buflen;
424
 
    uint8_t * buf = ipc_serialize( pk, &buflen );
425
 
    int ret = queuemsg( client, buf, buflen );
426
 
    tr_free( buf );
427
 
    return ret;
428
 
}
429
 
 
430
 
int
431
 
msgresp( struct client * client, int64_t tag, enum ipc_msg id )
432
 
{
433
 
    uint8_t * buf;
434
 
    size_t    buflen;
435
 
    int       ret;
436
 
 
437
 
    if( 0 >= tag )
438
 
    {
439
 
        return 0;
440
 
    }
441
 
 
442
 
    buf = ipc_mkempty( client->ipc, &buflen, id, tag );
443
 
    ret = queuemsg( client, buf, buflen );
444
 
    free( buf );
445
 
 
446
 
    return ret;
447
 
}
448
 
 
449
 
void
450
 
defmsg( enum ipc_msg id UNUSED, benc_val_t * val UNUSED, int64_t tag,
451
 
        void * arg )
452
 
{
453
 
    struct client * client = arg;
454
 
 
455
 
    msgresp( client, tag, IPC_MSG_NOTSUP );
456
 
}
457
 
 
458
 
void
459
 
noopmsg( enum ipc_msg id UNUSED, benc_val_t * val UNUSED, int64_t tag,
460
 
         void * arg )
461
 
{
462
 
    struct client * client = arg;
463
 
 
464
 
    msgresp( client, tag, IPC_MSG_OK );
465
 
}
466
 
 
467
 
void
468
 
addmsg1( enum ipc_msg id UNUSED, benc_val_t * val, int64_t tag, void * arg )
469
 
{
470
 
    struct client * client = arg;
471
 
    benc_val_t      pk, * added;
472
 
    int             ii, tor;
473
 
 
474
 
    if( !tr_bencIsList( val ) )
475
 
    {
476
 
        msgresp( client, tag, IPC_MSG_BAD );
477
 
        return;
478
 
    }
479
 
 
480
 
    added = ipc_initval( client->ipc, IPC_MSG_INFO, tag, &pk, TYPE_LIST );
481
 
    if( NULL == added )
482
 
    {
483
 
        errnomsg( "failed to build message" );
484
 
        byebye( client->ev, EVBUFFER_EOF, NULL );
485
 
        return;
486
 
    }
487
 
 
488
 
    for( ii = 0; ii < val->val.l.count; ii++ )
489
 
    {
490
 
        tr_benc * file = &val->val.l.vals[ii];
491
 
        if( !tr_bencIsString( file ) )
492
 
            continue;
493
 
 
494
 
        /* XXX need to somehow inform client of skipped or failed files */
495
 
        tor = torrent_add_file( file->val.s.s, NULL, -1 );
496
 
        if( TORRENT_ID_VALID( tor ) )
497
 
        {
498
 
            if( 0 > ipc_addinfo( added, tor, torrent_handle( tor ), 0 ) )
499
 
            {
500
 
                errnomsg( "failed to build message" );
501
 
                tr_bencFree( &pk );
502
 
                byebye( client->ev, EVBUFFER_EOF, NULL );
503
 
                return;
504
 
            }
505
 
        }
506
 
    }
507
 
 
508
 
    queuepkmsg( client, &pk );
509
 
    tr_bencFree( &pk );
510
 
}
511
 
 
512
 
void
513
 
addmsg2( enum ipc_msg id UNUSED, benc_val_t * dict, int64_t tag, void * arg )
514
 
{
515
 
    struct client * client = arg;
516
 
    benc_val_t    * val, pk;
517
 
    int             tor, start;
518
 
    const char    * dir;
519
 
 
520
 
    if( !tr_bencIsDict( dict ) )
521
 
    {
522
 
        msgresp( client, tag, IPC_MSG_BAD );
523
 
        return;
524
 
    }
525
 
 
526
 
    val   = tr_bencDictFind( dict, "directory" );
527
 
    dir   = tr_bencIsString( val ) ? val->val.s.s : NULL;
528
 
    val   = tr_bencDictFind( dict, "autostart" );
529
 
    start = tr_bencIsInt( val ) ? (val->val.i!=0) : -1;
530
 
    val   = tr_bencDictFind( dict, "data" );
531
 
    if( tr_bencIsString( val ) )
532
 
    {
533
 
        /* XXX detect duplicates and return a message indicating so */
534
 
        tor = torrent_add_data( ( uint8_t * )val->val.s.s, val->val.s.i,
535
 
                                dir, start );
536
 
    }
537
 
    else
538
 
    {
539
 
        val = tr_bencDictFind( dict, "file" );
540
 
        if( !tr_bencIsString( val ) )
541
 
        {
542
 
            msgresp( client, tag, IPC_MSG_BAD );
543
 
            return;
544
 
        }
545
 
        /* XXX detect duplicates and return a message indicating so */
546
 
        tor = torrent_add_file( val->val.s.s, dir, start );
547
 
    }
548
 
 
549
 
    if( TORRENT_ID_VALID( tor ) )
550
 
    {
551
 
        val = ipc_initval( client->ipc, IPC_MSG_INFO, tag, &pk, TYPE_LIST );
552
 
        if( NULL == val )
553
 
        {
554
 
            errnomsg( "failed to build message" );
555
 
            byebye( client->ev, EVBUFFER_EOF, NULL );
556
 
            return;
557
 
        }
558
 
        if( 0 > ipc_addinfo( val, tor, torrent_handle( tor ), 0 ) )
559
 
        {
560
 
            errnomsg( "failed to build message" );
561
 
            tr_bencFree( &pk );
562
 
            byebye( client->ev, EVBUFFER_EOF, NULL );
563
 
            return;
564
 
        }
565
 
 
566
 
        queuepkmsg( client, &pk );
567
 
        tr_bencFree( &pk );
568
 
    }
569
 
    else
570
 
    {
571
 
        msgresp( client, tag, IPC_MSG_FAIL );
572
 
    }
573
 
}
574
 
 
575
 
void
576
 
quitmsg( enum ipc_msg id UNUSED, benc_val_t * val UNUSED, int64_t tag UNUSED,
577
 
         void * arg UNUSED )
578
 
{
579
 
    server_quit();
580
 
}
581
 
 
582
 
void
583
 
intmsg( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg )
584
 
{
585
 
    struct client * client = arg;
586
 
    int             num;
587
 
 
588
 
    if( !tr_bencIsInt( val ) )
589
 
    {
590
 
        msgresp( client, tag, IPC_MSG_BAD );
591
 
        return;
592
 
    }
593
 
 
594
 
    num = MAX( INT_MIN, MIN( INT_MAX, val->val.i ) );
595
 
    switch( id )
596
 
    {
597
 
        case IPC_MSG_AUTOMAP:
598
 
            torrent_enable_port_mapping( num ? 1 : 0 );
599
 
            break;
600
 
        case IPC_MSG_AUTOSTART:
601
 
            torrent_set_autostart( num ? 1 : 0 );
602
 
            break;
603
 
        case IPC_MSG_DOWNLIMIT:
604
 
            torrent_set_downlimit( num );
605
 
            break;
606
 
        case IPC_MSG_PEX:
607
 
            torrent_set_pex( num ? 1 : 0 );
608
 
            break;
609
 
        case IPC_MSG_PORT:
610
 
            torrent_set_port( num );
611
 
            break;
612
 
        case IPC_MSG_UPLIMIT:
613
 
            torrent_set_uplimit( num );
614
 
            break;
615
 
        default:
616
 
            assert( 0 );
617
 
            return;
618
 
    }
619
 
 
620
 
    msgresp( client, tag, IPC_MSG_OK );
621
 
}
622
 
 
623
 
void
624
 
strmsg( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg )
625
 
{
626
 
    struct client * client = arg;
627
 
 
628
 
    if( !tr_bencIsString( val ) )
629
 
    {
630
 
        msgresp( client, tag, IPC_MSG_BAD );
631
 
        return;
632
 
    }
633
 
 
634
 
    switch( id )
635
 
    {
636
 
        case IPC_MSG_CRYPTO:
637
 
            if( !strcasecmp( val->val.s.s, "required" ) )
638
 
                torrent_set_encryption( TR_ENCRYPTION_REQUIRED );
639
 
            else if( !strcasecmp( val->val.s.s, "preferred" ) )
640
 
                torrent_set_encryption( TR_ENCRYPTION_PREFERRED );
641
 
            else if( !strcasecmp( val->val.s.s, "tolerated" ) )
642
 
                torrent_set_encryption( TR_PLAINTEXT_PREFERRED );
643
 
            else {
644
 
                msgresp(client, tag, IPC_MSG_BAD);
645
 
                return;
646
 
            }
647
 
            break;
648
 
 
649
 
        case IPC_MSG_DIR:
650
 
            torrent_set_directory( val->val.s.s );
651
 
            break;
652
 
        default:
653
 
            assert( 0 );
654
 
            return;
655
 
    }
656
 
 
657
 
    msgresp( client, tag, IPC_MSG_OK );
658
 
}
659
 
 
660
 
void
661
 
infomsg( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg )
662
 
{
663
 
    struct client * client = arg;
664
 
    benc_val_t      pk, * pkinf, * typelist, * idlist, * idval;
665
 
    int             all, types, ii, tor;
666
 
    void          * iter;
667
 
    enum ipc_msg    respid;
668
 
    int         ( * addfunc )( benc_val_t *, int, int );
669
 
 
670
 
    all = 0;
671
 
    switch( id )
672
 
    {
673
 
        case IPC_MSG_GETINFOALL:
674
 
            all = 1;
675
 
            /* FALLTHROUGH; */
676
 
        case IPC_MSG_GETINFO:
677
 
            respid = IPC_MSG_INFO;
678
 
            addfunc = addinfo;
679
 
            break;
680
 
        case IPC_MSG_GETSTATALL:
681
 
            all = 1;
682
 
            /* FALLTHROUGH */
683
 
        case IPC_MSG_GETSTAT:
684
 
            respid = IPC_MSG_STAT;
685
 
            addfunc = addstat;
686
 
            break;
687
 
        default:
688
 
            assert( 0 );
689
 
            return;
690
 
    }
691
 
 
692
 
    /* initialize packet */
693
 
    pkinf = ipc_initval( client->ipc, respid, tag, &pk, TYPE_LIST );
694
 
    if( NULL == pkinf )
695
 
    {
696
 
        errnomsg( "failed to build message" );
697
 
        byebye( client->ev, EVBUFFER_EOF, NULL );
698
 
        return;
699
 
    }
700
 
 
701
 
    /* add info/status for all torrents */
702
 
    if( all )
703
 
    {
704
 
        if( !tr_bencIsList( val ) )
705
 
        {
706
 
            msgresp( client, tag, IPC_MSG_BAD );
707
 
            tr_bencFree( &pk );
708
 
            return;
709
 
        }
710
 
        types = ipc_infotypes( respid, val );
711
 
        iter = NULL;
712
 
        while( NULL != ( iter = torrent_iter( iter, &tor ) ) )
713
 
        {
714
 
            if( 0 > addfunc( pkinf, tor, types ) )
715
 
            {
716
 
                errnomsg( "failed to build message" );
717
 
                tr_bencFree( &pk );
718
 
                byebye( client->ev, EVBUFFER_EOF, NULL );
719
 
                return;
720
 
            }
721
 
        }
722
 
    }
723
 
    /* add info/status for the requested IDs */
724
 
    else
725
 
    {
726
 
        if( !tr_bencIsDict( val ) )
727
 
        {
728
 
            msgresp( client, tag, IPC_MSG_BAD );
729
 
            tr_bencFree( &pk );
730
 
            return;
731
 
        }
732
 
        typelist = tr_bencDictFind( val, "type" );
733
 
        idlist   = tr_bencDictFind( val, "id" );
734
 
        if( !tr_bencIsList(typelist) || !tr_bencIsList(idlist) )
735
 
        {
736
 
            msgresp( client, tag, IPC_MSG_BAD );
737
 
            tr_bencFree( &pk );
738
 
            return;
739
 
        }
740
 
        types = ipc_infotypes( respid, typelist );
741
 
        for( ii = 0; idlist->val.l.count > ii; ii++ )
742
 
        {
743
 
            idval = &idlist->val.l.vals[ii];
744
 
            if( TYPE_INT != idval->type || !TORRENT_ID_VALID( idval->val.i ) )
745
 
            {
746
 
                continue;
747
 
            }
748
 
            tor = idval->val.i;
749
 
            if( 0 > addfunc( pkinf, idval->val.i, types ) )
750
 
            {
751
 
                errnomsg( "failed to build message" );
752
 
                tr_bencFree( &pk );
753
 
                byebye( client->ev, EVBUFFER_EOF, NULL );
754
 
                return;
755
 
            }
756
 
        }
757
 
    }
758
 
 
759
 
    queuepkmsg( client, &pk );
760
 
    tr_bencFree( &pk );
761
 
}
762
 
 
763
 
int
764
 
addinfo( benc_val_t * list, int id, int types )
765
 
{
766
 
    tr_torrent * tor = torrent_handle( id );
767
 
    return tor ? ipc_addinfo( list, id, tor, types ) : 0;
768
 
}
769
 
 
770
 
int
771
 
addstat( benc_val_t * list, int id, int types )
772
 
{
773
 
    tr_torrent * tor = torrent_handle( id );
774
 
    return tor ? ipc_addstat( list, id, tor, types ) : 0;
775
 
}
776
 
 
777
 
void
778
 
tormsg( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg )
779
 
{
780
 
    struct client * client = arg;
781
 
    benc_val_t    * idval;
782
 
    int             ii, all;
783
 
    void          * iter;
784
 
    void        ( * func )( int );
785
 
 
786
 
    all = 0;
787
 
    switch( id )
788
 
    {
789
 
        case IPC_MSG_REMOVEALL:
790
 
            all = 1;
791
 
            /* FALLTHROUGH */
792
 
        case IPC_MSG_REMOVE:
793
 
            func = torrent_remove;
794
 
            break;
795
 
        case IPC_MSG_STARTALL:
796
 
            all = 1;
797
 
            /* FALLTHROUGH */
798
 
        case IPC_MSG_START:
799
 
            func = torrent_start;
800
 
            break;
801
 
        case IPC_MSG_STOPALL:
802
 
            all = 1;
803
 
            /* FALLTHROUGH */
804
 
        case IPC_MSG_STOP:
805
 
            func = torrent_stop;
806
 
            break;
807
 
        case IPC_MSG_VERIFY:
808
 
            all = 0;
809
 
            func = torrent_verify;
810
 
            break;
811
 
        default:
812
 
            assert( 0 );
813
 
            return;
814
 
    }
815
 
 
816
 
    /* remove/start/stop all torrents */
817
 
    if( all )
818
 
    {
819
 
        iter = NULL;
820
 
        while( NULL != ( iter = torrent_iter( iter, &ii ) ) )
821
 
        {
822
 
            func( ii );
823
 
            if( torrent_remove == func )
824
 
            {
825
 
                iter = NULL;
826
 
            }
827
 
        }
828
 
    }
829
 
    /* remove/start/stop requested list of torrents */
830
 
    else
831
 
    {
832
 
        if( !tr_bencIsList( val ) )
833
 
        {
834
 
            msgresp( client, tag, IPC_MSG_BAD );
835
 
            return;
836
 
        }
837
 
        for( ii = 0; val->val.l.count > ii; ii++ )
838
 
        {
839
 
            idval = &val->val.l.vals[ii];
840
 
            if( TYPE_INT != idval->type || !TORRENT_ID_VALID( idval->val.i ) )
841
 
            {
842
 
                continue;
843
 
            }
844
 
            func( idval->val.i );
845
 
        }
846
 
    }
847
 
 
848
 
    msgresp( client, tag, IPC_MSG_OK );
849
 
}
850
 
 
851
 
void
852
 
lookmsg( enum ipc_msg id UNUSED, benc_val_t * val, int64_t tag, void * arg )
853
 
{
854
 
    struct client * client = arg;
855
 
    int             ii;
856
 
    benc_val_t    * hash, pk, * pkinf;
857
 
    int64_t         found;
858
 
 
859
 
    if( !tr_bencIsList( val ) )
860
 
    {
861
 
        msgresp( client, tag, IPC_MSG_BAD );
862
 
        return;
863
 
    }
864
 
 
865
 
    pkinf = ipc_initval( client->ipc, IPC_MSG_INFO, tag, &pk, TYPE_LIST );
866
 
    if( NULL == pkinf )
867
 
    {
868
 
        errnomsg( "failed to build message" );
869
 
        byebye( client->ev, EVBUFFER_EOF, NULL );
870
 
        return;
871
 
    }
872
 
 
873
 
    for( ii = 0; val->val.l.count > ii; ii++ )
874
 
    {
875
 
        hash = &val->val.l.vals[ii];
876
 
        if( !tr_bencIsString(hash) || SHA_DIGEST_LENGTH * 2 != hash->val.s.i )
877
 
        {
878
 
            tr_bencFree( &pk );
879
 
            msgresp( client, tag, IPC_MSG_BAD );
880
 
            return;
881
 
        }
882
 
        found = torrent_lookup( ( uint8_t * )hash->val.s.s );
883
 
        if( !TORRENT_ID_VALID( found ) )
884
 
        {
885
 
            continue;
886
 
        }
887
 
        if( 0 > ipc_addinfo( pkinf, found, torrent_handle( found ), IPC_INF_HASH ) )
888
 
        {
889
 
            errnomsg( "failed to build message" );
890
 
            tr_bencFree( &pk );
891
 
            byebye( client->ev, EVBUFFER_EOF, NULL );
892
 
            return;
893
 
        }
894
 
    }
895
 
 
896
 
    queuepkmsg( client, &pk );
897
 
    tr_bencFree( &pk );
898
 
}
899
 
 
900
 
void
901
 
prefmsg( enum ipc_msg id, benc_val_t * val UNUSED, int64_t tag, void * arg )
902
 
{
903
 
    struct client * client = arg;
904
 
    uint8_t       * buf;
905
 
    size_t          buflen;
906
 
    const char    * strval;
907
 
 
908
 
    switch( id )
909
 
    {
910
 
        case IPC_MSG_GETAUTOMAP:
911
 
            buf = ipc_mkint( client->ipc, &buflen, IPC_MSG_AUTOMAP, tag,
912
 
                             torrent_get_port_mapping() );
913
 
            break;
914
 
        case IPC_MSG_GETAUTOSTART:
915
 
            buf = ipc_mkint( client->ipc, &buflen, IPC_MSG_AUTOSTART, tag,
916
 
                             torrent_get_autostart() );
917
 
            break;
918
 
        case IPC_MSG_GETCRYPTO:
919
 
            switch(torrent_get_encryption()) {
920
 
                case TR_ENCRYPTION_REQUIRED:  strval = "required"; break;
921
 
                case TR_ENCRYPTION_PREFERRED: strval = "preferred"; break;
922
 
                case TR_PLAINTEXT_PREFERRED:  strval = "tolerated"; break;
923
 
                default: assert(0); return;
924
 
            }
925
 
            buf = ipc_mkstr(client->ipc, &buflen, IPC_MSG_CRYPTO, tag, strval);
926
 
            break;
927
 
        case IPC_MSG_GETDIR:
928
 
            buf = ipc_mkstr( client->ipc, &buflen, IPC_MSG_DIR, tag,
929
 
                             torrent_get_directory() );
930
 
            break;
931
 
        case IPC_MSG_GETDOWNLIMIT:
932
 
            buf = ipc_mkint( client->ipc, &buflen, IPC_MSG_DOWNLIMIT, tag,
933
 
                             torrent_get_downlimit() );
934
 
            break;
935
 
        case IPC_MSG_GETPEX:
936
 
            buf = ipc_mkint( client->ipc, &buflen, IPC_MSG_PEX, tag,
937
 
                             torrent_get_pex() );
938
 
            break;
939
 
        case IPC_MSG_GETPORT:
940
 
            buf = ipc_mkint( client->ipc, &buflen, IPC_MSG_PORT, tag,
941
 
                             torrent_get_port() );
942
 
            break;
943
 
        case IPC_MSG_GETUPLIMIT:
944
 
            buf = ipc_mkint( client->ipc, &buflen, IPC_MSG_UPLIMIT, tag,
945
 
                             torrent_get_uplimit() );
946
 
            break;
947
 
        default:
948
 
            assert( 0 );
949
 
            return;
950
 
    }
951
 
 
952
 
    queuemsg( client, buf, buflen );
953
 
    free( buf );
954
 
}
955
 
 
956
 
void
957
 
supmsg( enum ipc_msg id UNUSED, benc_val_t * val, int64_t tag, void * arg )
958
 
{
959
 
    struct client  * client = arg;
960
 
    int              ii;
961
 
    benc_val_t       pk, *pkval;
962
 
    enum ipc_msg     found;
963
 
 
964
 
    if( !tr_bencIsList( val ) )
965
 
    {
966
 
        msgresp( client, tag, IPC_MSG_BAD );
967
 
        return;
968
 
    }
969
 
 
970
 
    pkval = ipc_initval( client->ipc, IPC_MSG_SUP, tag, &pk, TYPE_LIST );
971
 
    if( NULL == pkval )
972
 
    {
973
 
        errnomsg( "failed to build message" );
974
 
        byebye( client->ev, EVBUFFER_EOF, NULL );
975
 
        return;
976
 
    }
977
 
    /* XXX look at other initval to make sure we free pk */
978
 
    if( tr_bencListReserve( pkval, val->val.l.count ) )
979
 
    {
980
 
        errnomsg( "failed to build message" );
981
 
        tr_bencFree( &pk );
982
 
        byebye( client->ev, EVBUFFER_EOF, NULL );
983
 
        return;
984
 
    }
985
 
 
986
 
    for( ii = 0; val->val.l.count > ii; ii++ )
987
 
    {
988
 
        tr_benc * name = &val->val.l.vals[ii];
989
 
        if( !tr_bencIsString( name ) )
990
 
        {
991
 
            tr_bencFree( &pk );
992
 
            msgresp( client, tag, IPC_MSG_BAD );
993
 
            return;
994
 
        }
995
 
        found = ipc_msgid( client->ipc, name->val.s.s );
996
 
        if( IPC__MSG_COUNT == found || !ipc_ishandled( client->ipc, found ) )
997
 
        {
998
 
            continue;
999
 
        }
1000
 
        tr_bencInitStr( tr_bencListAdd( pkval ),
1001
 
                        name->val.s.s, name->val.s.i, 1 );
1002
 
    }
1003
 
 
1004
 
    queuepkmsg( client, &pk );
1005
 
    tr_bencFree( &pk );
1006
 
}