source: trunk/macosx/IPCController.m @ 2227

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

Add client/server name to IPC version handshake.

  • Property svn:keywords set to Date Rev Author Id
File size: 27.3 KB
Line 
1/******************************************************************************
2 * $Id: IPCController.m 2227 2007-06-29 02:21:29Z joshe $
3 *
4 * Copyright (c) 2007 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 <sys/types.h>
26#include <sys/socket.h>
27#include <sys/un.h>
28#include <assert.h>
29#include <errno.h>
30#include <string.h>
31#include <unistd.h>
32
33#include "bencode.h"
34#include "ipcparse.h"
35#include "transmission.h"
36
37#import "IPCController.h"
38#import "Torrent.h"
39
40static void
41getaddr( struct sockaddr_un * );
42static NSArray *
43bencarray( benc_val_t * val, int type );
44static void
45msg_lookup   ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
46static void
47msg_info     ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
48void
49msg_infoall  ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
50void
51msg_action   ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
52void
53msg_actionall( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
54void
55msg_addold   ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
56void
57msg_addnew   ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
58void
59msg_getbool  ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
60void
61msg_getint   ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
62void
63msg_getstr   ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
64void
65msg_setbool  ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
66void
67msg_setint   ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
68void
69msg_setstr   ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
70void
71msg_empty    ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
72void
73msg_sup      ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
74static void
75msg_default  ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
76
77@interface IPCClient : NSObject
78{
79    NSFileHandle    * _handle;
80    struct ipc_info * _ipc;
81    IPCController   * _controller;
82    NSMutableData   * _buf;
83}
84
85- (id)              initClient: (IPCController *) controller
86                         funcs: (struct ipc_funcs *) funcs
87                        handle: (NSFileHandle *) handle;
88- (IPCController *) controller;
89- (struct ipc_info *)      ipc;
90- (void)               gotdata: (NSNotification *) notification;
91- (BOOL)              sendresp: (uint8_t *) buf
92                          size: (size_t) size;
93- (BOOL)         sendrespEmpty: (enum ipc_msg) msgid
94                           tag: (int64_t) tag;
95- (BOOL)           sendrespInt: (enum ipc_msg) msgid
96                           tag: (int64_t) tag
97                           val: (int64_t) val;
98- (BOOL)           sendrespStr: (enum ipc_msg) msgid
99                           tag: (int64_t) tag
100                           val: (NSString *) val;
101- (void)          sendrespInfo: (enum ipc_msg) respid
102                           tag: (int64_t) tag
103                      torrents: (NSArray *) tors
104                         types: (int) types;
105
106@end
107
108@interface IPCController (Private)
109
110- (void)  newclient: (NSNotification *) notification;
111- (void) killclient: (IPCClient *) client;
112
113@end
114
115@implementation IPCController
116
117- (id) init
118{
119    struct sockaddr_un sun;
120
121    self = [super init];
122    if( nil == self )
123        return nil;
124
125    getaddr( &sun );
126    unlink( sun.sun_path );
127    _sock    = [[NSSocketPort alloc]
128                   initWithProtocolFamily: PF_UNIX
129                               socketType: SOCK_STREAM
130                                 protocol: 0
131                                  address: [NSData dataWithBytes: &sun
132                                                          length: sizeof(sun)]];
133    _listen  = [[NSFileHandle alloc]
134                   initWithFileDescriptor: [_sock socket]
135                           closeOnDealloc: YES];
136    _funcs   = ipc_initmsgs();
137    _clients = [[NSMutableArray alloc] init];
138
139    /* XXX is this error checking bogus? */
140    if( nil  == _sock    ||
141        nil  == _listen  ||
142        NULL == _funcs   ||
143        nil  == _clients ||
144        0 > ipc_addmsg( _funcs, IPC_MSG_ADDMANYFILES, msg_addold    ) ||
145        0 > ipc_addmsg( _funcs, IPC_MSG_ADDONEFILE,   msg_addnew    ) ||
146        0 > ipc_addmsg( _funcs, IPC_MSG_AUTOMAP,      msg_setbool   ) ||
147        0 > ipc_addmsg( _funcs, IPC_MSG_AUTOSTART,    msg_setbool   ) ||
148        0 > ipc_addmsg( _funcs, IPC_MSG_DIR,          msg_setstr    ) ||
149        0 > ipc_addmsg( _funcs, IPC_MSG_DOWNLIMIT,    msg_setint    ) ||
150        0 > ipc_addmsg( _funcs, IPC_MSG_GETAUTOMAP,   msg_getbool   ) ||
151        0 > ipc_addmsg( _funcs, IPC_MSG_GETAUTOSTART, msg_getbool   ) ||
152        0 > ipc_addmsg( _funcs, IPC_MSG_GETDIR,       msg_getstr    ) ||
153        0 > ipc_addmsg( _funcs, IPC_MSG_GETDOWNLIMIT, msg_getint    ) ||
154        0 > ipc_addmsg( _funcs, IPC_MSG_GETINFO,      msg_info      ) ||
155        0 > ipc_addmsg( _funcs, IPC_MSG_GETINFOALL,   msg_infoall   ) ||
156        0 > ipc_addmsg( _funcs, IPC_MSG_GETPEX,       msg_getbool   ) ||
157        0 > ipc_addmsg( _funcs, IPC_MSG_GETPORT,      msg_getint    ) ||
158        0 > ipc_addmsg( _funcs, IPC_MSG_GETSTAT,      msg_info      ) ||
159        0 > ipc_addmsg( _funcs, IPC_MSG_GETSTATALL,   msg_infoall   ) ||
160        0 > ipc_addmsg( _funcs, IPC_MSG_GETUPLIMIT,   msg_getint    ) ||
161        0 > ipc_addmsg( _funcs, IPC_MSG_LOOKUP,       msg_lookup    ) ||
162        0 > ipc_addmsg( _funcs, IPC_MSG_NOOP,         msg_empty     ) ||
163        0 > ipc_addmsg( _funcs, IPC_MSG_PEX,          msg_setbool   ) ||
164        0 > ipc_addmsg( _funcs, IPC_MSG_PORT,         msg_setint    ) ||
165        0 > ipc_addmsg( _funcs, IPC_MSG_QUIT,         msg_empty     ) ||
166        0 > ipc_addmsg( _funcs, IPC_MSG_REMOVE,       msg_action    ) ||
167        0 > ipc_addmsg( _funcs, IPC_MSG_REMOVEALL,    msg_actionall ) ||
168        0 > ipc_addmsg( _funcs, IPC_MSG_START,        msg_action    ) ||
169        0 > ipc_addmsg( _funcs, IPC_MSG_STARTALL,     msg_actionall ) ||
170        0 > ipc_addmsg( _funcs, IPC_MSG_STOP,         msg_action    ) ||
171        0 > ipc_addmsg( _funcs, IPC_MSG_STOPALL,      msg_actionall ) ||
172        0 > ipc_addmsg( _funcs, IPC_MSG_SUP,          msg_sup       ) ||
173        0 > ipc_addmsg( _funcs, IPC_MSG_UPLIMIT,      msg_setint    ) )
174    {
175        [self release];
176        return nil;
177    }
178    ipc_setdefmsg( _funcs, msg_default );
179
180    [[NSNotificationCenter defaultCenter]
181        addObserver: self
182           selector: @selector(newclient:)
183               name: NSFileHandleConnectionAcceptedNotification
184             object: _listen];
185    [_listen acceptConnectionInBackgroundAndNotify];
186
187    return self;
188}
189
190- (void) dealloc
191{
192    struct sockaddr_un sun;
193
194    [[NSNotificationCenter defaultCenter] removeObserver: self];
195    [_listen  release];
196    [_sock    release];
197    [_clients release];
198    ipc_freemsgs( _funcs );
199    getaddr( &sun );
200    unlink( sun.sun_path );
201    [super dealloc];
202}
203
204- (id) delegate
205{
206    return _delegate;
207}
208
209- (void) setDelegate: (id) newdelegate
210{
211    _delegate = newdelegate;
212}
213
214@end
215
216@implementation IPCController (Private)
217
218- (void) newclient: (NSNotification *) notification
219{
220    NSDictionary * info;
221    NSFileHandle * handle;
222    NSNumber     * error;
223    IPCClient    * client;
224
225    info   = [notification userInfo];
226    handle = [info objectForKey: NSFileHandleNotificationFileHandleItem];
227    error  = [info objectForKey: @"NSFileHandleError"];
228
229    if( nil != error )
230    {
231        NSLog( @"Failed to accept IPC socket connection: %@", error );
232        return;
233    }
234
235    [_listen acceptConnectionInBackgroundAndNotify];
236
237    if( nil == handle )
238        return;
239
240    client = [[IPCClient alloc]
241                 initClient: self
242                      funcs: _funcs
243                     handle: handle];
244    if( nil == client )
245        return;
246
247    [_clients addObject:client];
248    [client release];
249}
250
251- (void) killclient: (IPCClient *) client
252{
253    [_clients removeObject: client];
254}
255
256@end
257
258@implementation IPCClient
259
260- (id) initClient: (IPCController *) controller
261            funcs: (struct ipc_funcs *) funcs
262           handle: (NSFileHandle *) handle
263{
264    uint8_t * buf;
265    size_t    size;
266
267    self = [super init];
268    if( nil == self )
269        return nil;
270
271    _handle     = [handle retain];
272    _ipc        = ipc_newcon( funcs );
273    _controller = controller;
274    _buf        = [[NSMutableData alloc] init];
275
276    buf = ipc_mkvers( &size, "Transmission MacOS X " VERSION_STRING );
277    if( NULL == _ipc || nil == _buf || NULL == buf ||
278        ![self sendresp: buf size: size] )
279    {
280        [self release];
281        return nil;
282    }
283
284    [[NSNotificationCenter defaultCenter]
285        addObserver: self
286           selector: @selector(gotdata:)
287               name: NSFileHandleReadCompletionNotification
288             object: _handle];
289    [_handle readInBackgroundAndNotify];
290
291    return self;
292}
293
294- (void) dealloc
295{
296    [[NSNotificationCenter defaultCenter] removeObserver: self];
297    [_handle release];
298    [_buf    release];
299    ipc_freecon( _ipc );
300    [super   dealloc];
301}
302
303- (IPCController *) controller
304{
305    return _controller;
306}
307
308- (struct ipc_info *) ipc
309{
310    return _ipc;
311}
312
313- (void) gotdata: (NSNotification *) notification
314{
315    NSDictionary * info;
316    NSData       * data;
317    NSNumber     * error;
318    ssize_t        res;
319
320    info  = [notification userInfo];
321    data  = [info objectForKey: NSFileHandleNotificationDataItem];
322    error = [info objectForKey: @"NSFileHandleError"];
323
324    if( nil != error )
325    {
326        NSLog( @"Failed to read from IPC socket connection: %@", error );
327        [_controller killclient: self];
328        return;
329    }
330
331    if( nil == data || 0 == [data length] )
332    {
333        [_controller killclient: self];
334        return;
335    }
336
337    [_handle readInBackgroundAndNotify];
338    [_buf appendData: data];
339
340    if( IPC_MIN_MSG_LEN > [_buf length] )
341        return;
342
343    res = ipc_parse( _ipc, [_buf mutableBytes], [_buf length], self );
344
345    if( 0 > res )
346    {
347        switch( errno )
348        {
349            case EPERM:
350                NSLog( @"IPC client has unsupported protocol version" );
351                break;
352            case EINVAL:
353                NSLog( @"IPC protocol parse error" );
354                break;
355            default:
356                NSLog( @"IPC parsing failed" );
357                break;
358        }
359        [_controller killclient: self];
360        return;
361    }
362    else if( 0 < res )
363    {
364        assert( res <= [_buf length]);
365        if( res < [_buf length])
366        {
367            memmove( [_buf mutableBytes], [_buf bytes] + res,
368                     [_buf length] - res );
369        }
370        [_buf setLength: ([_buf length] - res)];
371    }
372}
373
374- (BOOL) sendresp: (uint8_t *) buf
375             size: (size_t) size
376{
377    @try
378    {
379        [_handle writeData: [NSData dataWithBytesNoCopy: buf
380                                                 length: size
381                                           freeWhenDone: YES]];
382        return YES;
383    }
384    @catch( NSException * ex )
385    {
386        NSLog( @"Failed to write to IPC socket connection" );
387        return NO;
388    }
389}
390
391- (BOOL) sendrespEmpty: (enum ipc_msg) msgid
392                   tag: (int64_t) tag
393{
394    uint8_t * buf;
395    size_t    size;
396
397    buf = ipc_mkempty( _ipc, &size, msgid, tag );
398    if( NULL == buf )
399        return FALSE;
400
401    return [self sendresp: buf
402                     size: size];
403}
404
405- (BOOL) sendrespInt: (enum ipc_msg) msgid
406                 tag: (int64_t) tag
407                 val: (int64_t) val
408{
409    uint8_t * buf;
410    size_t    size;
411
412    buf = ipc_mkint( _ipc, &size, msgid, tag, val );
413    if( NULL == buf )
414        return FALSE;
415
416    return [self sendresp: buf
417                     size: size];
418}
419
420- (BOOL) sendrespStr: (enum ipc_msg) msgid
421                 tag: (int64_t) tag
422                 val: (NSString *) val
423{
424    uint8_t       * buf;
425    size_t          size;
426    NSData        * data;
427    NSMutableData * sucky;
428
429    if( [val canBeConvertedToEncoding: NSUTF8StringEncoding] )
430        buf = ipc_mkstr( _ipc, &size, msgid, tag,
431                         [val cStringUsingEncoding: NSUTF8StringEncoding] );
432    else
433    {
434        data = [val dataUsingEncoding: NSUTF8StringEncoding
435                 allowLossyConversion: YES];
436        /* XXX this sucks, I should add a length argument to ipc_mkstr() */
437        sucky = [NSMutableData dataWithData: data];
438        [sucky appendBytes: "" length: 1];
439        buf = ipc_mkstr( _ipc, &size, msgid, tag, [sucky bytes] );
440    }
441    if( NULL == buf )
442        return FALSE;
443
444    return [self sendresp: buf
445                     size: size];
446}
447
448- (void) sendrespInfo: (enum ipc_msg) respid
449                  tag: (int64_t) tag
450             torrents: (NSArray *) tors
451                types: (int) types
452{
453    benc_val_t     packet, * pkinf;
454    NSEnumerator * enumerator;
455    Torrent      * tor;
456    uint8_t      * buf;
457    size_t         size;
458    int            res;
459
460    pkinf = ipc_initval( _ipc, respid, tag, &packet, TYPE_LIST );
461    if( NULL == pkinf )
462        goto fail;
463    if( tr_bencListReserve( pkinf, [tors count] ) )
464    {
465        tr_bencFree( &packet );
466        goto fail;
467    }
468
469    enumerator = [tors objectEnumerator];
470    while( nil != ( tor = [enumerator nextObject] ) )
471    {
472        if( IPC_MSG_INFO == respid )
473            res = ipc_addinfo( pkinf, [tor torrentID], [tor torrentInfo], types );
474        else
475            res = ipc_addstat( pkinf, [tor torrentID], [tor torrentStat], types );
476        if( 0 > res )
477        {
478            tr_bencFree( &packet );
479            goto fail;
480        }
481    }
482
483    buf = ipc_mkval( &packet, &size );
484    tr_bencFree( &packet );
485    if( NULL == buf )
486        goto fail;
487    [self sendresp: buf size: size ];
488    return;
489
490  fail:
491    NSLog( @"Failed to create IPC reply packet" );
492    [_controller killclient: self];
493}
494
495
496@end
497
498void
499getaddr( struct sockaddr_un * sun )
500{
501    bzero( sun, sizeof *sun );
502    sun->sun_family = AF_LOCAL;
503    strlcpy( sun->sun_path, tr_getPrefsDirectory(), sizeof sun->sun_path );
504    strlcat( sun->sun_path, "/socket", sizeof sun->sun_path );
505}
506
507NSArray *
508bencarray( benc_val_t * val, int type )
509{
510    int              ii;
511    NSMutableArray * ret;
512    benc_val_t     * item;
513
514    assert( TYPE_STR == type || TYPE_INT == type );
515
516    if( NULL == val || TYPE_LIST != val->type )
517        return nil;
518
519    ret = [NSMutableArray arrayWithCapacity: val->val.l.count];
520    for( ii = 0; ii < val->val.l.count; ii++ )
521    {
522        item = &val->val.l.vals[ii];
523        if( type != item->type )
524            return nil;
525        if( TYPE_STR == type )
526        {
527            [ret addObject: [NSString stringWithCString: item->val.s.s
528                                               encoding: NSUTF8StringEncoding]];
529        }
530        else
531        {
532            [ret addObject: [NSNumber numberWithLongLong: (long long) item->val.i]];
533        }
534    }
535
536    return ret;
537}
538
539void
540msg_lookup( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
541{
542    IPCClient      * client = arg;
543    NSArray        * hashes, * tors;
544    benc_val_t       packet, * pkinf;
545    NSEnumerator   * enumerator;
546    Torrent        * tor;
547    uint8_t        * buf;
548    size_t           size;
549
550    hashes = bencarray( val, TYPE_STR );
551    if( NULL == hashes )
552    {
553        [client sendrespEmpty: IPC_MSG_BAD tag: tag];
554        return;
555    }
556
557    tors  = [[[client controller] delegate] ipcGetTorrentsByHash: hashes];
558    [client sendrespInfo: IPC_MSG_INFO
559                     tag: tag
560                torrents: tors
561                   types: IPC_INF_HASH];
562}
563
564void
565msg_info( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
566{
567    IPCClient  * client = arg;
568    enum ipc_msg respid;
569    benc_val_t * typesval;
570    int          types;
571    NSArray    * ids, * tors;
572
573    if( NULL == val || TYPE_DICT != val->type )
574        goto bad;
575
576    typesval = tr_bencDictFind( val, "type" );
577    if( NULL == typesval || TYPE_LIST != typesval->type ||
578        nil == ( ids = bencarray( tr_bencDictFind( val, "id" ), TYPE_INT ) ) )
579        goto bad;
580
581    respid = ( IPC_MSG_GETINFO == msgid ? IPC_MSG_INFO : IPC_MSG_STAT );
582    tors   = [[[client controller] delegate] ipcGetTorrentsByID: ids];
583    types  = ipc_infotypes( respid, typesval );
584    [client sendrespInfo: respid tag: tag torrents: tors types: types];
585    return;
586
587  bad:
588    NSLog( @"Got bad IPC packet" );
589    [client sendrespEmpty: IPC_MSG_BAD tag: tag];
590}
591
592void
593msg_infoall( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
594{
595    IPCClient  * client = arg;
596    enum ipc_msg respid;
597    int          types;
598    NSArray    * tors;
599
600    if( NULL == val || TYPE_LIST != val->type )
601    {
602        NSLog( @"Got bad IPC packet" );
603        [client sendrespEmpty: IPC_MSG_BAD tag: tag];
604        return;
605    }
606
607    respid = ( IPC_MSG_GETINFOALL == msgid ? IPC_MSG_INFO : IPC_MSG_STAT );
608    tors   = [[[client controller] delegate] ipcGetTorrentsByID: nil];
609    types  = ipc_infotypes( respid, val );
610    [client sendrespInfo: respid tag: tag torrents: tors types: types];
611}
612
613void
614msg_action( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
615{
616    IPCClient * client = arg;
617    BOOL        res;
618    NSArray   * ids, * tors;
619    id          delegate;
620
621    ids = bencarray( val, TYPE_INT );
622    if( nil == ids )
623    {
624        NSLog( @"Got bad IPC packet" );
625        [client sendrespEmpty: IPC_MSG_BAD tag: tag];
626        return;
627    }
628
629    delegate = [[client controller] delegate];
630    tors     = [delegate ipcGetTorrentsByID: ids];
631    switch( msgid )
632    {
633        case IPC_MSG_REMOVE:
634            res = [delegate ipcRemoveTorrents: tors];
635            break;
636        case IPC_MSG_START:
637            res = [delegate ipcStartTorrents: tors];
638            break;
639        case IPC_MSG_STOP:
640            res = [delegate ipcStopTorrents: tors];
641            break;
642        default:
643            assert( 0 );
644            return;
645    }
646
647    if( res )
648        [client sendrespEmpty: IPC_MSG_OK tag: tag];
649    else
650        [client sendrespEmpty: IPC_MSG_FAIL tag: tag];
651}
652
653void
654msg_actionall( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
655{
656    IPCClient * client = arg;
657    BOOL        res;
658    NSArray   * tors;
659    id          delegate;
660
661    delegate = [[client controller] delegate];
662    tors     = [delegate ipcGetTorrentsByID: nil];
663    switch( msgid )
664    {
665        case IPC_MSG_REMOVEALL:
666            res = [delegate ipcRemoveTorrents: tors];
667            break;
668        case IPC_MSG_STARTALL:
669            res = [delegate ipcStartTorrents: tors];
670            break;
671        case IPC_MSG_STOPALL:
672            res = [delegate ipcStopTorrents: tors];
673            break;
674        default:
675            assert( 0 );
676            return;
677    }
678
679    if( res )
680        [client sendrespEmpty: IPC_MSG_OK tag: tag];
681    else
682        [client sendrespEmpty: IPC_MSG_FAIL tag: tag];
683}
684
685void
686msg_addold( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
687{
688    IPCClient * client = arg;
689    NSArray   * paths;
690    BOOL        res;
691
692    paths = bencarray( val, TYPE_STR );
693    if( nil == paths )
694    {
695        NSLog( @"Got bad IPC packet" );
696        [client sendrespEmpty: IPC_MSG_BAD tag: tag];
697        return;
698    }
699
700    /* XXX should send back info message with torrent IDs */
701    if( [[[client controller] delegate] ipcAddTorrents: paths] )
702        [client sendrespEmpty: IPC_MSG_OK tag: tag];
703    else
704        [client sendrespEmpty: IPC_MSG_FAIL tag: tag];
705}
706
707void
708msg_addnew( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
709{
710    IPCClient  * client = arg;
711    benc_val_t * fileval, * dataval, * dirval, * autoval;
712    NSString   * file, * dir;
713    NSData     * data;
714    BOOL         autobool, res;
715
716    if( NULL == val || TYPE_DICT != val->type )
717        goto bad;
718
719    fileval = tr_bencDictFind( val, "file" );
720    dataval = tr_bencDictFind( val, "data" );
721    dirval  = tr_bencDictFind( val, "directory" );
722    autoval = tr_bencDictFind( val, "autostart" );
723    if( ( ( NULL == fileval || TYPE_STR != fileval->type )   &&
724          ( NULL == dataval || TYPE_STR != dataval->type ) ) ||
725        ( ( NULL != fileval && TYPE_STR == fileval->type )   &&
726          ( NULL != dataval && TYPE_STR == dataval->type ) ) ||
727          ( NULL != dirval  && TYPE_STR != dirval->type  )   ||
728          ( NULL != autoval && TYPE_INT != autoval->type ) )
729        goto bad;
730
731    dir = ( NULL == dirval ? nil :
732            [NSString stringWithCString: dirval->val.s.s
733                               encoding: NSUTF8StringEncoding] );
734    autobool = ( NULL == autoval || 0 == autoval->val.i ? NO : YES );
735
736    if( NULL != fileval )
737    {
738        file = [NSString stringWithCString: fileval->val.s.s
739                                  encoding: NSUTF8StringEncoding];
740        if( NULL == autoval )
741            res = [[[client controller] delegate]
742                      ipcAddTorrentFile: file
743                              directory: dir];
744        else
745            res = [[[client controller] delegate]
746                      ipcAddTorrentFileAutostart: file
747                                       directory: dir
748                                       autostart: autobool];
749    }
750    else
751    {
752        data = [NSData dataWithBytes: dataval->val.s.s
753                              length: dataval->val.s.i];
754        if( NULL == autoval )
755            res = [[[client controller] delegate]
756                      ipcAddTorrentData: data
757                              directory: dir];
758        else
759            res = [[[client controller] delegate]
760                      ipcAddTorrentDataAutostart: data
761                                       directory: dir
762                                       autostart: autobool];
763    }
764
765    /* XXX should send back info message with torrent ID */
766    if( res )
767        [client sendrespEmpty: IPC_MSG_OK tag: tag];
768    else
769        [client sendrespEmpty: IPC_MSG_FAIL tag: tag];
770    return;
771
772  bad:
773    NSLog( @"Got bad IPC packet" );
774    [client sendrespEmpty: IPC_MSG_BAD tag: tag];
775}
776
777void
778msg_getbool( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
779{
780    IPCClient * client = arg;
781
782    switch( msgid )
783    {
784        case IPC_MSG_GETAUTOMAP:
785        case IPC_MSG_GETAUTOSTART:
786        case IPC_MSG_GETPEX:
787            [client sendrespEmpty: IPC_MSG_FAIL tag: tag];
788            break;
789        default:
790            assert( 0 );
791            break;
792    }
793}
794
795void
796msg_getint( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
797{
798    IPCClient * client = arg;
799
800    switch( msgid )
801    {
802        case IPC_MSG_GETDOWNLIMIT:
803        case IPC_MSG_GETPORT:
804        case IPC_MSG_GETUPLIMIT:
805            [client sendrespEmpty: IPC_MSG_FAIL tag: tag];
806            break;
807        default:
808            assert( 0 );
809            break;
810    }
811}
812
813void
814msg_getstr( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
815{
816    IPCClient * client = arg;
817
818    switch( msgid )
819    {
820        case IPC_MSG_GETDIR:
821            [client sendrespEmpty: IPC_MSG_FAIL tag: tag];
822            break;
823        default:
824            assert( 0 );
825            break;
826    }
827}
828
829void
830msg_setbool( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
831{
832    IPCClient * client = arg;
833
834    if( NULL == val || TYPE_INT != val->type )
835    {
836        NSLog( @"Got bad IPC packet" );
837        [client sendrespEmpty: IPC_MSG_BAD tag: tag];
838        return;
839    }
840
841    switch( msgid )
842    {
843        case IPC_MSG_AUTOMAP:
844        case IPC_MSG_AUTOSTART:
845        case IPC_MSG_PEX:
846            [client sendrespEmpty: IPC_MSG_FAIL tag: tag];
847            break;
848        default:
849            assert( 0 );
850            break;
851    }
852}
853
854void
855msg_setint( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
856{
857    IPCClient * client = arg;
858
859    if( NULL == val || TYPE_INT != val->type )
860    {
861        NSLog( @"Got bad IPC packet" );
862        [client sendrespEmpty: IPC_MSG_BAD tag: tag];
863        return;
864    }
865
866    switch( msgid )
867    {
868        case IPC_MSG_DOWNLIMIT:
869        case IPC_MSG_PORT:
870        case IPC_MSG_UPLIMIT:
871            [client sendrespEmpty: IPC_MSG_FAIL tag: tag];
872            break;
873        default:
874            assert( 0 );
875            break;
876    }
877}
878
879void
880msg_setstr( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
881{
882    IPCClient * client = arg;
883
884    if( NULL == val || TYPE_STR != val->type )
885    {
886        NSLog( @"Got bad IPC packet" );
887        [client sendrespEmpty: IPC_MSG_BAD tag: tag];
888        return;
889    }
890
891    switch( msgid )
892    {
893        case IPC_MSG_DIR:
894            [client sendrespEmpty: IPC_MSG_FAIL tag: tag];
895            break;
896        default:
897            assert( 0 );
898            break;
899    }
900}
901
902void
903msg_empty( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
904{
905    IPCClient * client = arg;
906
907    switch( msgid )
908    {
909        case IPC_MSG_NOOP:
910            [client sendrespEmpty: IPC_MSG_OK tag: tag];
911            break;
912        case IPC_MSG_QUIT:
913            [[[client controller] delegate] ipcQuit];
914            [client sendrespEmpty: IPC_MSG_OK tag: tag];
915            break;
916        default:
917            assert( 0 );
918            break;
919    }
920}
921
922void
923msg_sup( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
924{
925    IPCClient       * client = arg;
926    benc_val_t        packet, * pkval, * name;
927    struct ipc_info * ipc;
928    int               ii;
929    enum ipc_msg      found;
930    uint8_t         * buf;
931    size_t            size;
932
933    if( NULL == val || TYPE_LIST != val->type )
934        goto bad;
935
936    ipc   = [client ipc];
937    pkval = ipc_initval( ipc, IPC_MSG_SUP, tag, &packet, TYPE_LIST );
938    if( NULL == pkval )
939        goto fail;
940    if( tr_bencListReserve( pkval, val->val.l.count ) )
941    {
942        tr_bencFree( &packet );
943        goto fail;
944    }
945
946    for( ii = 0; val->val.l.count > ii; ii++ )
947    {
948        name = &val->val.l.vals[ii];
949        if( NULL == name || TYPE_STR != name->type )
950            goto bad;
951        found = ipc_msgid( ipc, name->val.s.s );
952        if( IPC__MSG_COUNT == found || !ipc_ishandled( ipc, found ) )
953        {
954            continue;
955        }
956        tr_bencInitStr( tr_bencListAdd( pkval ),
957                        name->val.s.s, name->val.s.i, 1 );
958    }
959
960    buf = ipc_mkval( &packet, &size );
961    tr_bencFree( &packet );
962    if( NULL == buf )
963        goto fail;
964    [client sendresp: buf size: size ];
965    return;
966
967  bad:
968    NSLog( @"Got bad IPC packet" );
969    [client sendrespEmpty: IPC_MSG_BAD tag: tag];
970    return;
971
972  fail:
973    NSLog( @"Failed to create IPC reply packet" );
974    [[client controller] killclient: client];
975}
976
977void
978msg_default( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
979{
980    IPCClient * client = arg;
981
982    [client sendrespEmpty: IPC_MSG_NOTSUP tag: tag];
983}
Note: See TracBrowser for help on using the repository browser.