source: branches/daemon/daemon/server.c @ 1617

Last change on this file since 1617 was 1617, checked in by joshe, 15 years ago

Add a daemon frontend.

  • Property svn:keywords set to Date Rev Author Id
File size: 23.0 KB
Line 
1/******************************************************************************
2 * $Id: server.c 1617 2007-03-31 20:00:40Z joshe $
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 "bsdtree.h"
40#include "bencode.h"
41#include "errors.h"
42#include "ipc.h"
43#include "misc.h"
44#include "server.h"
45#include "torrents.h"
46
47/* time out clients after this many seconds */
48#define CLIENT_TIMEOUT          ( 60 )
49
50struct client
51{
52    int                  fd;
53    struct bufferevent * ev;
54    struct ipc_info      ipc;
55    RB_ENTRY( client )   link;
56};
57
58RB_HEAD( allclients, client );
59
60static void newclient( int, short, void * );
61static void noop     ( struct bufferevent *, void * );
62static void byebye   ( struct bufferevent *, short, void * );
63static void doread   ( struct bufferevent *, void * );
64static int  queuemsg ( struct client *, uint8_t *, size_t );
65static void msgresp  ( struct client *, int64_t, enum ipc_msg );
66static void defmsg   ( enum ipc_msg, benc_val_t *, int64_t, void * );
67static void noopmsg  ( enum ipc_msg, benc_val_t *, int64_t, void * );
68static void addmsg   ( enum ipc_msg, benc_val_t *, int64_t, void * );
69static void quitmsg  ( enum ipc_msg, benc_val_t *, int64_t, void * );
70static void intmsg   ( enum ipc_msg, benc_val_t *, int64_t, void * );
71static void strmsg   ( enum ipc_msg, benc_val_t *, int64_t, void * );
72static void infomsg  ( enum ipc_msg, benc_val_t *, int64_t, void * );
73static int  addinfo  ( benc_val_t *, int, int );
74static int  addstat  ( benc_val_t *, int, int );
75static void tormsg   ( enum ipc_msg, benc_val_t *, int64_t, void * );
76static void lookmsg  ( enum ipc_msg, benc_val_t *, int64_t, void * );
77static void prefmsg  ( enum ipc_msg, benc_val_t *, int64_t, void * );
78static void supmsg   ( enum ipc_msg, benc_val_t *, int64_t, void * );
79static int  clientcmp( struct client *, struct client * );
80
81RB_GENERATE_STATIC( allclients, client, link, clientcmp )
82INTCMP_FUNC( clientcmp, client, ev )
83
84static struct event_base * gl_base    = NULL;
85static struct ipc_funcs  * gl_tree    = NULL;
86static int                 gl_exiting = 0;
87static struct allclients   gl_clients = RB_INITIALIZER( &gl_clients );
88
89int
90server_init( struct event_base * base )
91{
92    assert( NULL == gl_base && NULL == gl_tree );
93    gl_base = base;
94    gl_tree = ipc_initmsgs();
95    if( NULL == gl_tree )
96    {
97        return -1;
98    }
99
100    if( 0 > ipc_addmsg( gl_tree, IPC_MSG_ADDFILES,     addmsg  ) ||
101        0 > ipc_addmsg( gl_tree, IPC_MSG_AUTOMAP,      intmsg  ) ||
102        0 > ipc_addmsg( gl_tree, IPC_MSG_AUTOSTART,    intmsg  ) ||
103        0 > ipc_addmsg( gl_tree, IPC_MSG_DOWNLIMIT,    intmsg  ) ||
104        0 > ipc_addmsg( gl_tree, IPC_MSG_DIR,          strmsg  ) ||
105        0 > ipc_addmsg( gl_tree, IPC_MSG_GETAUTOMAP,   prefmsg ) ||
106        0 > ipc_addmsg( gl_tree, IPC_MSG_GETAUTOSTART, prefmsg ) ||
107        0 > ipc_addmsg( gl_tree, IPC_MSG_GETDOWNLIMIT, prefmsg ) ||
108        0 > ipc_addmsg( gl_tree, IPC_MSG_GETDIR,       prefmsg ) ||
109        0 > ipc_addmsg( gl_tree, IPC_MSG_GETINFO,      infomsg ) ||
110        0 > ipc_addmsg( gl_tree, IPC_MSG_GETINFOALL,   infomsg ) ||
111        0 > ipc_addmsg( gl_tree, IPC_MSG_GETPORT,      prefmsg ) ||
112        0 > ipc_addmsg( gl_tree, IPC_MSG_GETSTAT,      infomsg ) ||
113        0 > ipc_addmsg( gl_tree, IPC_MSG_GETSTATALL,   infomsg ) ||
114        0 > ipc_addmsg( gl_tree, IPC_MSG_GETUPLIMIT,   prefmsg ) ||
115        0 > ipc_addmsg( gl_tree, IPC_MSG_GETSUP,       supmsg  ) ||
116        0 > ipc_addmsg( gl_tree, IPC_MSG_LOOKUP,       lookmsg ) ||
117        0 > ipc_addmsg( gl_tree, IPC_MSG_NOOP,         noopmsg ) ||
118        0 > ipc_addmsg( gl_tree, IPC_MSG_PORT,         intmsg  ) ||
119        0 > ipc_addmsg( gl_tree, IPC_MSG_QUIT,         quitmsg ) ||
120        0 > ipc_addmsg( gl_tree, IPC_MSG_REMOVE,       tormsg  ) ||
121        0 > ipc_addmsg( gl_tree, IPC_MSG_REMOVEALL,    tormsg  ) ||
122        0 > ipc_addmsg( gl_tree, IPC_MSG_START,        tormsg  ) ||
123        0 > ipc_addmsg( gl_tree, IPC_MSG_STARTALL,     tormsg  ) ||
124        0 > ipc_addmsg( gl_tree, IPC_MSG_STOP,         tormsg  ) ||
125        0 > ipc_addmsg( gl_tree, IPC_MSG_STOPALL,      tormsg  ) ||
126        0 > ipc_addmsg( gl_tree, IPC_MSG_UPLIMIT,      intmsg  ) )
127    {
128        return -1;
129    }
130
131    ipc_setdefmsg( gl_tree, defmsg );
132
133    return 0;
134}
135
136int
137server_listen( int fd )
138{
139    struct event * ev;
140    int flags;
141
142    assert( NULL != gl_base );
143
144    flags = fcntl( fd, F_GETFL );
145    if( 0 > flags )
146    {
147        errnomsg( "failed to get flags on socket" );
148        return -1;
149    }
150    if( 0 > fcntl( fd, F_SETFL, flags | O_NONBLOCK ) )
151    {
152        errnomsg( "failed to set flags on socket" );
153        return -1;
154    }
155
156    if( 0 > listen( fd, 5 ) )
157    {
158        errnomsg( "failed to listen on socket" );
159        return -1;
160    }
161
162    ev = malloc( sizeof *ev );
163    if( NULL == ev )
164    {
165        mallocmsg( sizeof *ev );
166        return -1;
167    }
168
169    event_set( ev, fd, EV_READ | EV_PERSIST, newclient, ev );
170    event_base_set( gl_base, ev );
171    event_add( ev, NULL );
172
173    return 0;
174}
175
176void
177newclient( int fd, short event UNUSED, void * arg )
178{
179    struct sockaddr_un   sun;
180    struct client      * client, * old;
181    socklen_t            socklen;
182    struct bufferevent * clev;
183    int                  clfd;
184    size_t               buflen;
185    uint8_t            * buf;
186
187    if( gl_exiting )
188    {
189        event_del( arg );
190        return;
191    }
192
193    for( ;; )
194    {
195        client = calloc( 1, sizeof *client );
196        if( NULL == client )
197        {
198            mallocmsg( sizeof *client );
199            return;
200        }
201
202        socklen = sizeof sun;
203        clfd = accept( fd, ( struct sockaddr * )&sun, &socklen );
204        if( 0 > clfd )
205        {
206            if( EWOULDBLOCK != errno && EAGAIN != errno &&
207                ECONNABORTED != errno )
208            {
209                errnomsg( "failed to accept ipc connection" );
210            }
211            free( client );
212            break;
213        }
214
215        clev = bufferevent_new( clfd, doread, noop, byebye, client );
216        if( NULL == clev )
217        {
218            close( clfd );
219            free( client );
220            mallocmsg( -1 );
221            return;
222        }
223        bufferevent_base_set( gl_base, clev );
224        bufferevent_settimeout( clev, CLIENT_TIMEOUT, CLIENT_TIMEOUT );
225
226        client->fd      = clfd;
227        ipc_newcon( &client->ipc, gl_tree );
228        client->ev      = clev;
229        old = RB_INSERT( allclients, &gl_clients, client );
230        assert( NULL == old );
231
232        bufferevent_enable( clev, EV_READ );
233        buf = ipc_mkvers( &buflen );
234        if( 0 > queuemsg( client, buf, buflen ) )
235        {
236            free( buf );
237            return;
238        }
239        free( buf );
240    }
241}
242
243void
244noop( struct bufferevent * ev UNUSED, void * arg UNUSED )
245{
246    /* libevent prior to 1.2 couldn't handle a NULL write callback */
247}
248
249void
250byebye( struct bufferevent * ev, short what, void * arg UNUSED )
251{
252    struct client * client, key;
253
254    if( !( EVBUFFER_EOF & what ) )
255    {
256        if( EVBUFFER_TIMEOUT & what )
257        {
258            errmsg( "client connection timed out" );
259        }
260        else if( EVBUFFER_READ & what )
261        {
262            errmsg( "read error on client connection" );
263        }
264        else if( EVBUFFER_WRITE & what )
265        {
266            errmsg( "write error on client connection" );
267        }
268        else if( EVBUFFER_ERROR & what )
269        {
270            errmsg( "error on client connection" );
271        }
272        else
273        {
274            errmsg( "unknown error on client connection: 0x%x", what );
275        }
276    }
277
278    bzero( &key, sizeof key );
279    key.ev = ev;
280    client = RB_FIND( allclients, &gl_clients, &key );
281    assert( NULL != client );
282    RB_REMOVE( allclients, &gl_clients, client );
283    bufferevent_free( ev );
284    close( client->fd );
285    free( client );
286}
287
288void
289doread( struct bufferevent * ev, void * arg )
290{
291    struct client * client = arg;
292    ssize_t         res;
293    uint8_t       * buf;
294    size_t          len;
295
296    assert( !gl_exiting );
297
298    buf = EVBUFFER_DATA( EVBUFFER_INPUT( ev ) );
299    len = EVBUFFER_LENGTH( EVBUFFER_INPUT( ev ) );
300
301    if( IPC_MIN_MSG_LEN > len )
302    {
303        return;
304    }
305
306    res = ipc_parse( &client->ipc, buf, len, client );
307
308    if( gl_exiting )
309    {
310        return;
311    }
312
313    if( 0 > res )
314    {
315        switch( errno )
316        {
317            case EPERM:
318                errmsg( "unsupported protocol version" );
319                break;
320            case EINVAL:
321                errmsg( "protocol parse error" );
322                break;
323            default:
324                errnomsg( "parsing failed" );
325                break;
326        }
327        byebye( ev, EVBUFFER_ERROR, NULL );
328    }
329    else if( 0 < res )
330    {
331        evbuffer_drain( EVBUFFER_INPUT( ev ), res );
332    }
333}
334
335int
336queuemsg( struct client * client, uint8_t * buf, size_t buflen )
337{
338    if( NULL == buf )
339    {
340        if( EPERM != errno )
341        {
342            errnomsg( "failed to build message" );
343            byebye( client->ev, EVBUFFER_EOF, NULL );
344        }
345        return -1;
346    }
347
348    if( 0 > bufferevent_write( client->ev, buf, buflen ) )
349    {
350        errnomsg( "failed to buffer %zd bytes of data for write", buflen );
351        return -1;
352    }
353
354    return 0;
355}
356
357void
358msgresp( struct client * client, int64_t tag, enum ipc_msg id )
359{
360    uint8_t * buf;
361    size_t    buflen;
362
363    if( 0 >= tag )
364    {
365        return;
366    }
367
368    buf = ipc_mkempty( &client->ipc, &buflen, id, tag );
369    queuemsg( client, buf, buflen );
370    free( buf );
371}
372
373void
374defmsg( enum ipc_msg id UNUSED, benc_val_t * val UNUSED, int64_t tag,
375        void * arg )
376{
377    struct client * client = arg;
378
379    msgresp( client, tag, IPC_MSG_NOTSUP );
380}
381
382void
383noopmsg( enum ipc_msg id UNUSED, benc_val_t * val UNUSED, int64_t tag,
384         void * arg )
385{
386    struct client * client = arg;
387
388    msgresp( client, tag, IPC_MSG_OK );
389}
390
391void
392addmsg( enum ipc_msg id UNUSED, benc_val_t * val, int64_t tag, void * arg )
393{
394    struct client * client = arg;
395    benc_val_t    * file;
396    int64_t       * added, tor;
397    int             ii;
398    size_t          count, buflen;
399    uint8_t       * buf;
400
401    if( NULL == val || TYPE_LIST != val->type )
402    {
403        msgresp( client, tag, IPC_MSG_NOTSUP );
404        return;
405    }
406
407    if( 0 < tag )
408    {
409        added = calloc( val->val.l.count, sizeof( added[0] ) );
410        if( NULL == added )
411        {
412            mallocmsg( val->val.l.count * sizeof( added[0] ) );
413            byebye( client->ev, EVBUFFER_EOF, NULL );
414            return;
415        }
416        count = 0;
417    }
418
419    for( ii = 0; ii < val->val.l.count; ii++ )
420    {
421        file = &val->val.l.vals[ii];
422        if( TYPE_STR != file->type )
423        {
424            continue;
425        }
426        /* XXX need to somehow inform client of skipped or failed files */
427        tor = torrent_add( file->val.s.s );
428        if( 0 < tag )
429        {
430            added[count] = tor;
431            count++;
432        }
433    }
434
435    if( 0 < tag )
436    {
437        buf = ipc_mkints( &client->ipc, &buflen, tag, IPC_MSG_INFO,
438                          count, added );
439        queuemsg( client, buf, buflen );
440        free( added );
441        free( buf );
442    }
443}
444
445void
446quitmsg( enum ipc_msg id UNUSED, benc_val_t * val UNUSED, int64_t tag UNUSED,
447         void * arg UNUSED )
448{
449    struct client * ii, * next;
450
451    torrent_exit( 0 );
452    gl_exiting = 1;
453
454    for( ii = RB_MIN( allclients, &gl_clients ); NULL != ii; ii = next )
455    {
456        next = RB_NEXT( allclients, &gl_clients, ii );
457        byebye( ii->ev, EVBUFFER_EOF, NULL );
458    }
459}
460
461void
462intmsg( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg )
463{
464    struct client * client = arg;
465    int             num;
466
467    if( NULL == val || TYPE_INT != val->type )
468    {
469        msgresp( client, tag, IPC_MSG_NOTSUP );
470        return;
471    }
472
473    num = MAX( INT_MIN, MIN( INT_MAX, val->val.i ) );
474    switch( id )
475    {
476        case IPC_MSG_AUTOMAP:
477            torrent_enable_port_mapping( num ? 1 : 0 );
478            break;
479        case IPC_MSG_AUTOSTART:
480            torrent_set_autostart( num ? 1 : 0 );
481            break;
482        case IPC_MSG_DOWNLIMIT:
483            torrent_set_downlimit( num );
484            break;
485        case IPC_MSG_PORT:
486            torrent_set_port( num );
487            break;
488        case IPC_MSG_UPLIMIT:
489            torrent_set_uplimit( num );
490            break;
491        default:
492            assert( 0 );
493            return;
494    }
495
496    msgresp( client, tag, IPC_MSG_OK );
497}
498
499void
500strmsg( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg )
501{
502    struct client * client = arg;
503
504    if( NULL == val || TYPE_STR != val->type )
505    {
506        msgresp( client, tag, IPC_MSG_NOTSUP );
507        return;
508    }
509
510    switch( id )
511    {
512        case IPC_MSG_DIR:
513            torrent_set_directory( val->val.s.s );
514            break;
515        default:
516            assert( 0 );
517            return;
518    }
519
520    msgresp( client, tag, IPC_MSG_OK );
521}
522
523void
524infomsg( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg )
525{
526    struct client * client = arg;
527    uint8_t       * buf;
528    size_t          buflen;
529    benc_val_t      pk, * pkinf, * typelist, * idlist, * idval;
530    int             all, types, ii, tor;
531    void          * iter;
532    enum ipc_msg    respid;
533    int         ( * addfunc )( benc_val_t *, int, int );
534
535    all = 0;
536    switch( id )
537    {
538        case IPC_MSG_GETINFOALL:
539            all = 1;
540            /* FALLTHROUGH; */
541        case IPC_MSG_GETINFO:
542            respid = IPC_MSG_INFO;
543            addfunc = addinfo;
544            break;
545        case IPC_MSG_GETSTATALL:
546            all = 1;
547            /* FALLTHROUGH */
548        case IPC_MSG_GETSTAT:
549            respid = IPC_MSG_STAT;
550            addfunc = addstat;
551            break;
552        default:
553            assert( 0 );
554            return;
555    }
556
557    /* initialize packet */
558    if( 0 > ipc_initinfo( &client->ipc, respid, tag, &pk, &pkinf ) )
559    {
560        errnomsg( "failed to build message" );
561        byebye( client->ev, EVBUFFER_EOF, NULL );
562        return;
563    }
564
565    /* add info/status for all torrents */
566    if( all )
567    {
568        if( NULL == val || TYPE_LIST != val->type )
569        {
570            msgresp( client, tag, IPC_MSG_NOTSUP );
571            tr_bencFree( &pk );
572            return;
573        }
574        types = ipc_infotypes( respid, val );
575        iter = NULL;
576        while( NULL != ( iter = torrent_iter( iter, &tor ) ) )
577        {
578            if( 0 > addfunc( pkinf, tor, types ) )
579            {
580                tr_bencFree( &pk );
581                byebye( client->ev, EVBUFFER_EOF, NULL );
582                return;
583            }
584        }
585    }
586    /* add info/status for the requested IDs */
587    else
588    {
589        if( NULL == val || TYPE_DICT != val->type )
590        {
591            msgresp( client, tag, IPC_MSG_NOTSUP );
592            tr_bencFree( &pk );
593            return;
594        }
595        typelist = tr_bencDictFind( val, "type" );
596        idlist   = tr_bencDictFind( val, "id" );
597        if( NULL == typelist || TYPE_LIST != typelist->type ||
598            NULL == idlist   || TYPE_LIST != idlist->type )
599        {
600            msgresp( client, tag, IPC_MSG_NOTSUP );
601            tr_bencFree( &pk );
602            return;
603        }
604        types = ipc_infotypes( respid, typelist );
605        for( ii = 0; idlist->val.l.count > ii; ii++ )
606        {
607            idval = &idlist->val.l.vals[ii];
608            if( TYPE_INT != idval->type || !TORRENT_ID_VALID( idval->val.i ) )
609            {
610                continue;
611            }
612            tor = idval->val.i;
613            if( 0 > addfunc( pkinf, idval->val.i, types ) )
614            {
615                tr_bencFree( &pk );
616                byebye( client->ev, EVBUFFER_EOF, NULL );
617                return;
618            }
619        }
620    }
621
622    /* generate packet data and send it */
623    buf = ipc_mkinfo( &pk, &buflen );
624    queuemsg( client, buf, buflen );
625    free( buf );
626    tr_bencFree( &pk );
627}
628
629int
630addinfo( benc_val_t * list, int id, int types )
631{
632    tr_info_t * inf;
633
634    inf = torrent_info( id );
635    if( NULL == inf )
636    {
637        return 0;
638    }
639
640    return ipc_addinfo( list, id, inf, types );
641}
642
643int
644addstat( benc_val_t * list, int id, int types )
645{
646    tr_stat_t * st;
647    tr_info_t * inf;
648
649    st = torrent_stat( id );
650    if( NULL == st )
651    {
652        return 0;
653    }
654    inf = torrent_info( id );
655    assert( NULL != inf );
656
657    return ipc_addstat( list, id, inf, st, types );
658}
659
660void
661tormsg( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg )
662{
663    struct client * client = arg;
664    benc_val_t    * idval;
665    int             ii, all;
666    void          * iter;
667    void        ( * func )( int );
668
669    all = 0;
670    switch( id )
671    {
672        case IPC_MSG_REMOVEALL:
673            all = 1;
674            /* FALLTHROUGH */
675        case IPC_MSG_REMOVE:
676            func = torrent_remove;
677            break;
678        case IPC_MSG_STARTALL:
679            all = 1;
680            /* FALLTHROUGH */
681        case IPC_MSG_START:
682            func = torrent_start;
683            break;
684        case IPC_MSG_STOPALL:
685            all = 1;
686            /* FALLTHROUGH */
687        case IPC_MSG_STOP:
688            func = torrent_stop;
689            break;
690        default:
691            assert( 0 );
692            return;
693    }
694
695    /* remove/start/stop all torrents */
696    if( all )
697    {
698        iter = NULL;
699        while( NULL != ( iter = torrent_iter( iter, &ii ) ) )
700        {
701            func( ii );
702        }
703    }
704    /* remove/start/stop requested list of torrents */
705    else
706    {
707        if( NULL == val || TYPE_LIST != val->type )
708        {
709            msgresp( client, tag, IPC_MSG_NOTSUP );
710            return;
711        }
712        for( ii = 0; val->val.l.count > ii; ii++ )
713        {
714            idval = &val->val.l.vals[ii];
715            if( TYPE_INT != idval->type || !TORRENT_ID_VALID( idval->val.i ) )
716            {
717                continue;
718            }
719            func( idval->val.i );
720        }
721    }
722
723    msgresp( client, tag, IPC_MSG_OK );
724}
725
726void
727lookmsg( enum ipc_msg id UNUSED, benc_val_t * val, int64_t tag, void * arg )
728{
729    struct client * client = arg;
730    uint8_t       * buf;
731    size_t          buflen;
732    int             ii;
733    benc_val_t    * hash, pk, * pkinf;
734    int64_t         found;
735    tr_info_t     * inf;
736
737    if( NULL == val || TYPE_LIST != val->type )
738    {
739        msgresp( client, tag, IPC_MSG_NOTSUP );
740        return;
741    }
742
743    if( 0 > ipc_initinfo( &client->ipc, IPC_MSG_INFO, tag, &pk, &pkinf ) )
744    {
745        byebye( client->ev, EVBUFFER_EOF, NULL );
746        return;
747    }
748
749    for( ii = 0; val->val.l.count > ii; ii++ )
750    {
751        hash = &val->val.l.vals[ii];
752        if( NULL == hash || TYPE_STR != hash->type ||
753            SHA_DIGEST_LENGTH * 2 != hash->val.s.i )
754        {
755            tr_bencFree( &pk );
756            msgresp( client, tag, IPC_MSG_NOTSUP );
757            return;
758        }
759        found = torrent_lookup( hash->val.s.s );
760        if( !TORRENT_ID_VALID( found ) )
761        {
762            continue;
763        }
764        inf = torrent_info( found );
765        assert( NULL != inf );
766        if( 0 > ipc_addinfo( pkinf, found, inf, IPC_INF_HASH ) )
767        {
768            tr_bencFree( &pk );
769            byebye( client->ev, EVBUFFER_EOF, NULL );
770            return;
771        }
772    }
773
774    buf = ipc_mkinfo( &pk, &buflen );
775    tr_bencFree( &pk );
776    queuemsg( client, buf, buflen );
777    free( buf );
778}
779
780void
781prefmsg( enum ipc_msg id, benc_val_t * val UNUSED, int64_t tag, void * arg )
782{
783    struct client * client = arg;
784    uint8_t       * buf;
785    size_t          buflen;
786
787    switch( id )
788    {
789        case IPC_MSG_GETAUTOMAP:
790            buf = ipc_mkint( &client->ipc, &buflen, IPC_MSG_AUTOMAP, tag,
791                             torrent_get_port_mapping() );
792            break;
793        case IPC_MSG_GETAUTOSTART:
794            buf = ipc_mkint( &client->ipc, &buflen, IPC_MSG_AUTOSTART, tag,
795                             torrent_get_autostart() );
796            break;
797        case IPC_MSG_GETDIR:
798            buf = ipc_mkstr( &client->ipc, &buflen, IPC_MSG_DIR, tag,
799                             torrent_get_directory() );
800            break;
801        case IPC_MSG_GETDOWNLIMIT:
802            buf = ipc_mkint( &client->ipc, &buflen, IPC_MSG_DOWNLIMIT, tag,
803                             torrent_get_downlimit() );
804            break;
805        case IPC_MSG_GETPORT:
806            buf = ipc_mkint( &client->ipc, &buflen, IPC_MSG_PORT, tag,
807                             torrent_get_port() );
808            break;
809        case IPC_MSG_GETUPLIMIT:
810            buf = ipc_mkint( &client->ipc, &buflen, IPC_MSG_UPLIMIT, tag,
811                             torrent_get_uplimit() );
812            break;
813        default:
814            assert( 0 );
815            return;
816    }
817
818    queuemsg( client, buf, buflen );
819    free( buf );
820}
821
822void
823supmsg( enum ipc_msg id UNUSED, benc_val_t * val, int64_t tag, void * arg )
824{
825    struct client  * client = arg;
826    uint8_t        * buf;
827    size_t           buflen;
828    int              ii, used;
829    benc_val_t     * name;
830    struct stritem * strs;
831    struct strlist   strlist;
832    enum ipc_msg     found;
833
834    if( NULL == val || TYPE_LIST != val->type )
835    {
836        msgresp( client, tag, IPC_MSG_NOTSUP );
837        return;
838    }
839
840    strs = calloc( val->val.l.count, sizeof *strs );
841    if( NULL == strs )
842    {
843        byebye( client->ev, EVBUFFER_EOF, NULL );
844        return;
845    }
846    used = 0;
847
848    for( ii = 0; val->val.l.count > ii; ii++ )
849    {
850        name = &val->val.l.vals[ii];
851        if( NULL == name || TYPE_STR != name->type )
852        {
853            free( strs );
854            msgresp( client, tag, IPC_MSG_NOTSUP );
855            return;
856        }
857        found = ipc_msgid( &client->ipc, name->val.s.s );
858        if( IPC__MSG_COUNT == found )
859        {
860            continue;
861        }
862        strs[used].str = name->val.s.s;
863        used++;
864    }
865
866    SLIST_INIT( &strlist );
867    while( 0 < used )
868    {
869        SLIST_INSERT_HEAD( &strlist, &strs[used-1], next );
870        used--;
871    }
872    buf = ipc_mkstrlist( &client->ipc, &buflen, IPC_MSG_SUP, tag, &strlist );
873    queuemsg( client, buf, buflen );
874    free( strs );
875}
Note: See TracBrowser for help on using the repository browser.