source: trunk/gtk/ipc.c @ 5125

Last change on this file since 5125 was 5125, checked in by charles, 14 years ago

(gtk) group the ipc functions by call order

  • Property svn:keywords set to Date Rev Author Id
File size: 31.8 KB
Line 
1/******************************************************************************
2 * $Id: ipc.c 5125 2008-02-26 21:05:13Z charles $
3 *
4 * Copyright (c) 2006-2008 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 <errno.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <unistd.h>
33
34#include <gtk/gtk.h>
35#include <glib/gi18n.h>
36
37#include <libevent/evutil.h>
38
39#include <libtransmission/transmission.h>
40#include <libtransmission/bencode.h>
41#include <libtransmission/ipcparse.h>
42
43#include "conf.h"
44#include "ipc.h"
45#include "tr-core.h"
46#include "tr-io.h"
47#include "tr-prefs.h"
48#include "tr-torrent.h"
49#include "util.h"
50
51#ifndef AF_LOCAL
52#define AF_LOCAL AF_UNIX
53#endif
54
55#ifndef SUN_LEN
56#define SUN_LEN( sun )                                                       \
57  ( sizeof( *(sun) ) - sizeof( (sun)->sun_path ) + strlen( (sun)->sun_path ) )
58#endif
59
60/* XXX error handling throughout this file is pretty bogus */
61
62enum contype { CON_SERV, CON_CLIENT };
63
64struct constate_serv
65{
66    GtkWindow * wind;
67    gpointer    core;
68};
69
70struct constate_client
71{
72    GMainLoop  * loop;
73    enum ipc_msg msg;
74    GList      * files;
75    gboolean   * succeeded;
76    unsigned int msgid;
77};
78
79struct constate
80{
81    GSource          * source;
82    int                fd;
83    enum contype       type;
84    struct ipc_funcs * msgs;
85    struct ipc_info  * ipc;
86    union
87    {
88        struct constate_serv   serv;
89        struct constate_client client;
90    } u;
91};
92
93/* this is only used on the server */
94static char *gl_sockpath = NULL;
95
96static gboolean
97simpleresp( struct constate * con, int64_t tag, enum ipc_msg id )
98{
99    uint8_t         * buf;
100    size_t            size;
101
102    buf = ipc_mkempty( con->ipc, &size, id, tag );
103    if( NULL == buf )
104    {
105        return FALSE;
106    }
107
108    io_send_keepdata( con->source, buf, size );
109
110    return TRUE;
111}
112
113static void
114all_default( enum ipc_msg id, benc_val_t * val UNUSED, int64_t tag, void * arg )
115{
116    switch( id )
117    {
118        case IPC_MSG_FAIL:
119        case IPC_MSG_NOTSUP:
120        case IPC_MSG_BAD:
121        case IPC_MSG_OK:
122            break;
123        default:
124            simpleresp( arg, tag, IPC_MSG_NOTSUP );
125            break;
126    }
127}
128
129static void
130destroycon(struct constate *con) {
131  con->source = NULL;
132
133  if(0 <= con->fd)
134    EVUTIL_CLOSESOCKET(con->fd);
135  con->fd = -1;
136  ipc_freecon( con->ipc );
137
138  switch(con->type) {
139    case CON_SERV:
140      break;
141    case CON_CLIENT:
142      ipc_freemsgs( con->msgs );
143      freestrlist(con->u.client.files);
144      g_main_loop_quit(con->u.client.loop);
145      break;
146  }
147}
148
149static void
150cli_io_sent( GSource * source UNUSED, size_t id, void *vdata )
151{
152  struct constate_client *cli = &((struct constate*)vdata)->u.client;
153
154  if(0 < id && cli->msgid == id) {
155    *(cli->succeeded) = TRUE;
156    destroycon(vdata);
157  }
158}
159
160static void
161client_sendmsg( struct constate * con )
162{
163    struct constate_client * cli = &con->u.client;
164    GList                  * ii;
165    uint8_t                * buf;
166    size_t                   size;
167    benc_val_t               packet, * val;
168    int                      saved;
169
170    switch( cli->msg )
171    {
172        case IPC_MSG_ADDMANYFILES:
173            val = ipc_initval( con->ipc, cli->msg, -1, &packet, TYPE_LIST );
174            if( NULL == val ||
175                tr_bencListReserve( val, g_list_length( cli->files ) ) )
176            {
177                perror( "malloc" );
178                destroycon( con );
179                return;
180            }
181            for( ii = cli->files; NULL != ii; ii = ii->next )
182            {
183                tr_bencInitStr( tr_bencListAdd( val ), ii->data, -1, 0 );
184            }
185            buf = ipc_mkval( &packet, &size );
186            saved = errno;
187            tr_bencFree( &packet );
188            g_list_free( cli->files );
189            cli->files = NULL;
190            break;
191        case IPC_MSG_QUIT:
192            buf = ipc_mkempty( con->ipc, &size, cli->msg, -1 );
193            saved = errno;
194            break;
195        default:
196            g_assert_not_reached();
197            return;
198    }
199
200    if( NULL == buf )
201    {
202        errno = saved;
203        perror( "malloc" );
204        destroycon( con );
205        return;
206    }
207
208    cli->msgid = io_send_keepdata( con->source, buf, size );
209}
210
211static size_t
212cli_io_received( GSource * source UNUSED, void * data, size_t len,
213                 void * vdata )
214{
215    struct constate        * con = vdata;
216    struct constate_client * cli = &con->u.client;
217    ssize_t                  res;
218
219    if( IPC_MIN_MSG_LEN > len )
220    {
221        return 0;
222    }
223
224    res = ipc_parse( con->ipc, data, len, con );
225
226    if( 0 > res )
227    {
228        switch( errno )
229        {
230            case EPERM:
231                g_message( _("Bad IPC protocol version") );
232                break;
233            case EINVAL:
234                g_message( _("IPC protocol parse error") );
235                break;
236            default:
237                g_message( _("IPC parsing failed: %s"), g_strerror( errno ) );
238                break;
239        }
240        destroycon( con );
241        return 0;
242    }
243
244    if( HASVERS( con->ipc ) && 0 == cli->msgid )
245    {
246        client_sendmsg( con );
247    }
248
249    return res;
250}
251
252static void
253all_io_closed(GSource *source UNUSED, void *vdata) {
254  struct constate *con = vdata;
255
256  destroycon(con);
257}
258
259static gboolean
260client_connect(char *path, struct constate *con) {
261  struct sockaddr_un addr;
262  uint8_t          * buf;
263  size_t             size;
264
265  if(0 > (con->fd = socket(AF_UNIX, SOCK_STREAM, 0))) {
266    g_message( _("Failed to create socket: %s"), g_strerror(errno));
267    return FALSE;
268  }
269
270  memset(&addr, 0,  sizeof(addr));
271  addr.sun_family = AF_UNIX;
272  strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
273
274  if(0 > connect(con->fd, (struct sockaddr*)&addr, SUN_LEN(&addr))) {
275    g_message( _("Failed to connect to %s: %s"), path, g_strerror(errno));
276    return FALSE;
277  }
278
279  con->source = io_new(con->fd, cli_io_sent, cli_io_received,
280                       all_io_closed, con);
281  if( NULL == con->source )
282  {
283      EVUTIL_CLOSESOCKET( con->fd );
284      return FALSE;
285  }
286
287  buf = ipc_mkvers( &size, "Transmission GTK+ " LONG_VERSION_STRING );
288  if( NULL == buf )
289  {
290      EVUTIL_CLOSESOCKET( con->fd );
291      return FALSE;
292  }
293
294  io_send_keepdata( con->source, buf, size );
295
296  return TRUE;
297}
298
299static gboolean
300blocking_client( enum ipc_msg msgid, GList * files )
301{
302
303  struct constate *con;
304  char *path;
305  gboolean ret = FALSE;
306
307  con = g_new0(struct constate, 1);
308  con->source = NULL;
309  con->fd = -1;
310  con->type = CON_CLIENT;
311
312  con->msgs = ipc_initmsgs();
313  if( NULL == con->msgs )
314  {
315      g_message( _("Failed to set up IPC: %s"), g_strerror( errno ) );
316      g_free( con );
317      return FALSE;
318  }
319
320  con->ipc = ipc_newcon( con->msgs );
321  if( NULL == con->ipc )
322  {
323      ipc_freemsgs( con->msgs );
324      g_free( con );
325      return FALSE;
326  }
327
328  ipc_setdefmsg( con->msgs, all_default );
329
330  con->u.client.loop = g_main_loop_new(NULL, TRUE);
331  con->u.client.msg = msgid;
332  con->u.client.files = files;
333  con->u.client.succeeded = &ret;
334  con->u.client.msgid = 0;
335
336  path = cf_sockname();
337  if(!client_connect(path, con)) {
338    g_free(path);
339    destroycon(con);
340    return FALSE;
341  }
342
343  g_main_loop_run(con->u.client.loop);
344
345  return ret;
346}
347
348gboolean
349ipc_sendfiles_blocking( GList * files )
350{
351    return blocking_client( IPC_MSG_ADDMANYFILES, files );
352}
353
354gboolean
355ipc_sendquit_blocking( void )
356{
357    return blocking_client( IPC_MSG_QUIT, NULL );
358}
359
360static void
361rmsock(void) {
362  if(NULL != gl_sockpath) {
363    unlink(gl_sockpath);
364    g_free(gl_sockpath);
365  }
366}
367
368static size_t
369srv_io_received( GSource * source UNUSED, void * data, size_t len,
370                 void * vdata )
371{
372    struct constate      * con = vdata;
373    struct constate_serv * srv = &con->u.serv;
374    ssize_t                res;
375
376    if( IPC_MIN_MSG_LEN > len )
377    {
378        return 0;
379    }
380
381    if( NULL == srv->core )
382    {
383        destroycon( con );
384    }
385
386    res = ipc_parse( con->ipc, data, len, con );
387
388    if( 0 > res )
389    {
390        switch( errno )
391        {
392            case EPERM:
393                errmsg( con->u.serv.wind, _("Bad IPC protocol version") );
394                break;
395            case EINVAL:
396                errmsg( con->u.serv.wind, _("IPC protocol parse error") );
397                break;
398            default:
399                errmsg( con->u.serv.wind, _("IPC parsing failed: %s"),
400                        g_strerror( errno ) );
401        }
402        destroycon( con );
403        return 0;
404    }
405
406    return res;
407}
408
409static void
410srv_io_accept(GSource *source UNUSED, int fd, struct sockaddr *sa UNUSED,
411              socklen_t len UNUSED, void *vdata) {
412  struct constate *con = vdata;
413  struct constate *newcon;
414  uint8_t        * buf;
415  size_t           size;
416
417  newcon = g_new(struct constate, 1);
418  memcpy(newcon, con, sizeof(*newcon));
419  newcon->fd = fd;
420
421  newcon->ipc = ipc_newcon( con->msgs );
422  if( NULL == newcon->ipc )
423  {
424      g_free( newcon );
425      EVUTIL_CLOSESOCKET( fd );
426      return;
427  }
428
429  newcon->source = io_new(fd, NULL, srv_io_received, all_io_closed, newcon);
430  if( NULL == newcon->source )
431  {
432      ipc_freecon( newcon->ipc );
433      g_free( newcon );
434      EVUTIL_CLOSESOCKET( fd );
435      return;
436  }
437
438  buf = ipc_mkvers( &size, "Transmission GTK+ " LONG_VERSION_STRING );
439  if( NULL == buf )
440  {
441      ipc_freecon( newcon->ipc );
442      g_free( newcon );
443      EVUTIL_CLOSESOCKET( fd );
444      return;
445  }
446
447  io_send_keepdata( newcon->source, buf, size );
448}
449
450/* open a local socket for clients connections */
451static void
452serv_bind(struct constate *con) {
453  struct sockaddr_un sa;
454
455  rmsock();
456  gl_sockpath = cf_sockname();
457
458  if(0 > (con->fd = socket(AF_LOCAL, SOCK_STREAM, 0)))
459    goto fail;
460
461  memset(&sa, 0,  sizeof(sa));
462  sa.sun_family = AF_LOCAL;
463  strncpy(sa.sun_path, gl_sockpath, sizeof(sa.sun_path) - 1);
464
465  /* unlink any existing socket file before trying to create ours */
466  unlink(gl_sockpath);
467  if(0 > bind(con->fd, (struct sockaddr *)&sa, SUN_LEN(&sa))) {
468    /* bind may fail if there was already a socket, so try twice */
469    unlink(gl_sockpath);
470    if(0 > bind(con->fd, (struct sockaddr *)&sa, SUN_LEN(&sa)))
471      goto fail;
472  }
473
474  if(0 > listen(con->fd, 5))
475    goto fail;
476
477  con->source = io_new_listening(con->fd, sizeof(struct sockaddr_un),
478                                 srv_io_accept, all_io_closed, con);
479
480  g_atexit(rmsock);
481
482  return;
483
484 fail:
485  errmsg(con->u.serv.wind, _("Failed to set up socket: %s"),
486         g_strerror(errno));
487  if(0 <= con->fd)
488    EVUTIL_CLOSESOCKET(con->fd);
489  con->fd = -1;
490  rmsock();
491}
492
493static void
494smsg_add( enum ipc_msg id UNUSED, benc_val_t * val, int64_t tag, void * arg )
495{
496    struct constate      * con = arg;
497    struct constate_serv * srv = &con->u.serv;
498    benc_val_t           * path;
499    int                    ii;
500    tr_ctor              * ctor;
501    GList                * list = NULL;
502
503    if( NULL == val || TYPE_LIST != val->type )
504    {
505        simpleresp( con, tag, IPC_MSG_BAD );
506        return;
507    }
508
509    ctor = tr_ctorNew( srv->core );
510
511    for( ii = 0; ii < val->val.l.count; ii++ )
512    {
513        path = val->val.l.vals + ii;
514        if( TYPE_STR == path->type &&
515            /* XXX somehow escape invalid utf-8 */
516            g_utf8_validate( path->val.s.s, path->val.s.i, NULL ) )
517        {
518            list = g_list_append( list, g_strndup( path->val.s.s, path->val.s.i ) );
519        }
520    }
521
522    if( list ) {
523        tr_core_add_list( srv->core, list, ctor );
524        tr_core_torrents_added( TR_CORE( srv->core ) );
525    }
526
527    /* XXX should send info response back with torrent ids */
528    simpleresp( con, tag, IPC_MSG_OK );
529}
530
531static void
532smsg_addone( enum ipc_msg id UNUSED, benc_val_t * val, int64_t tag,
533             void * arg )
534{
535    struct constate      * con = arg;
536    struct constate_serv * srv = &con->u.serv;
537    benc_val_t           * file, * data, * dir, * start;
538    tr_ctor              * ctor;
539
540    if( NULL == val || TYPE_DICT != val->type )
541    {
542        simpleresp( con, tag, IPC_MSG_BAD );
543        return;
544    }
545
546    file  = tr_bencDictFind( val, "file" );
547    data  = tr_bencDictFind( val, "data" );
548    dir   = tr_bencDictFind( val, "directory" );
549    start = tr_bencDictFind( val, "autostart" );
550
551    if( ( NULL != file  && TYPE_STR != file->type  ) ||
552        ( NULL != data  && TYPE_STR != data->type  ) ||
553        ( NULL != dir   && TYPE_STR != dir->type   ) ||
554        ( NULL != start && TYPE_INT != start->type ) )
555    {
556        simpleresp( con, tag, IPC_MSG_BAD );
557        return;
558    }
559
560    ctor = tr_ctorNew( tr_core_handle( srv->core ) );
561    if( dir )
562        tr_ctorSetDestination( ctor, TR_FORCE, dir->val.s.s );
563    if( file )
564        tr_ctorSetMetainfoFromFile( ctor, file->val.s.s );
565    if( data )
566        tr_ctorSetMetainfo( ctor, (uint8_t*)data->val.s.s, data->val.s.i );
567    if( start )
568        tr_ctorSetPaused( ctor, TR_FORCE, !start->val.i );
569
570    tr_core_add_ctor( TR_CORE( srv->core ), ctor );
571
572    tr_core_torrents_added( TR_CORE( srv->core ) );
573
574    /* XXX should send info response back with torrent ids */
575    simpleresp( con, tag, IPC_MSG_OK );
576}
577
578static void
579smsg_quit( enum ipc_msg id UNUSED, benc_val_t * val UNUSED, int64_t tag UNUSED,
580           void * arg UNUSED )
581{
582    struct constate      * con = arg;
583    struct constate_serv * srv = &con->u.serv;
584
585    tr_core_quit( srv->core );
586}
587
588static void
589smsg_noop( enum ipc_msg id UNUSED, benc_val_t * val UNUSED, int64_t tag,
590           void * arg )
591{
592    simpleresp( arg, tag, IPC_MSG_OK );
593}
594
595static TrTorrent *
596findtorid( TrCore * core, int id, GtkTreeIter * iter )
597{
598    GtkTreeModel * model;
599    GtkTreeIter    myiter;
600    int            rowid;
601    TrTorrent    * tor;
602
603    if( NULL == iter )
604    {
605        iter = &myiter;
606    }
607
608    model = tr_core_model( core );
609    if( gtk_tree_model_get_iter_first( model, iter ) )
610    {
611        do
612        {
613            gtk_tree_model_get( model, iter, MC_ID, &rowid, -1 );
614            if( rowid == id )
615            {
616                gtk_tree_model_get( model, iter, MC_TORRENT, &tor, -1 );
617                g_object_unref( tor );
618                return tor;
619            }
620        }
621        while( gtk_tree_model_iter_next( model, iter ) );
622    }
623
624    return NULL;
625}
626
627static int
628addinfo( TrTorrent * tor, enum ipc_msg msgid, int torid, int types,
629         benc_val_t * val )
630{
631    if( IPC_MSG_INFO == msgid )
632    {
633        const tr_info * inf = tr_torrent_info( tor );
634        return ipc_addinfo( val, torid, inf, types );
635    }
636    else
637    {
638        const tr_stat * st = tr_torrent_stat( tor );
639        return ipc_addstat( val, torid, st, types );
640    }
641}
642
643static void
644smsg_info( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg )
645{
646    struct constate      * con = arg;
647    struct constate_serv * srv = &con->u.serv;
648    enum ipc_msg           respid;
649    benc_val_t           * ids, * types, * idval, packet, * pkval;
650    int                    typeflags, ii;
651    TrTorrent            * tor;
652    uint8_t              * buf;
653    size_t                 size;
654
655    if( NULL == val || TYPE_DICT != val->type )
656    {
657        simpleresp( con, tag, IPC_MSG_BAD );
658        return;
659    }
660
661    respid = ( IPC_MSG_GETINFO == id ? IPC_MSG_INFO : IPC_MSG_STAT );
662    ids    = tr_bencDictFind( val, "id" );
663    types  = tr_bencDictFind( val, "types" );
664    if( NULL == ids   || TYPE_LIST != ids->type ||
665        NULL == types || TYPE_LIST != types->type )
666    {
667        simpleresp( con, tag, IPC_MSG_BAD );
668        return;
669    }
670    typeflags = ipc_infotypes( respid, types );
671
672    pkval = ipc_initval( con->ipc, respid, tag, &packet, TYPE_LIST );
673    if( NULL == pkval )
674    {
675        simpleresp( con, tag, IPC_MSG_FAIL );
676        return;
677    }
678    for( ii = 0; ids->val.l.count > ii; ii++ )
679    {
680        idval = &ids->val.l.vals[ii];
681        if( TYPE_INT != idval->type || !TORRENT_ID_VALID( idval->val.i ) ||
682            NULL == ( tor = findtorid( srv->core, idval->val.i, NULL ) ) )
683        {
684            continue;
685        }
686        if( 0 > addinfo( tor, respid, idval->val.i, typeflags, pkval ) )
687        {
688            tr_bencFree( &packet );
689            simpleresp( con, tag, IPC_MSG_FAIL );
690            return;
691        }
692    }
693
694    buf = ipc_mkval( &packet, &size );
695    tr_bencFree( &packet );
696    if( NULL == buf )
697    {
698        simpleresp( con, tag, IPC_MSG_FAIL );
699    }
700    else
701    {
702        io_send_keepdata( con->source, buf, size );
703    }
704}
705
706static void
707smsg_infoall( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg )
708{
709    struct constate      * con = arg;
710    struct constate_serv * srv = &con->u.serv;
711    enum ipc_msg           respid;
712    benc_val_t             packet, * pkval;
713    int                    typeflags;
714    GtkTreeModel         * model;
715    GtkTreeIter            iter;
716    int                    rowid;
717    TrTorrent            * tor;
718    uint8_t              * buf;
719    size_t                 size;
720
721    if( NULL == val || TYPE_LIST != val->type )
722    {
723        simpleresp( con, tag, IPC_MSG_BAD );
724        return;
725    }
726
727    respid = ( IPC_MSG_GETINFOALL == id ? IPC_MSG_INFO : IPC_MSG_STAT );
728    typeflags = ipc_infotypes( respid, val );
729
730    pkval = ipc_initval( con->ipc, respid, tag, &packet, TYPE_LIST );
731    if( NULL == pkval )
732    {
733        simpleresp( con, tag, IPC_MSG_FAIL );
734        return;
735    }
736
737    model = tr_core_model( srv->core );
738    if( gtk_tree_model_get_iter_first( model, &iter ) )
739    {
740        do
741        {
742            gtk_tree_model_get( model, &iter, MC_ID, &rowid,
743                                MC_TORRENT, &tor, -1 );
744            g_object_unref( tor );
745            if( 0 > addinfo( tor, respid, rowid, typeflags, pkval ) )
746            {
747                tr_bencFree( &packet );
748                simpleresp( con, tag, IPC_MSG_FAIL );
749                return;
750            }
751        }
752        while( gtk_tree_model_iter_next( model, &iter ) );
753    }
754
755    buf = ipc_mkval( &packet, &size );
756    tr_bencFree( &packet );
757    if( NULL == buf )
758    {
759        simpleresp( con, tag, IPC_MSG_FAIL );
760    }
761    else
762    {
763        io_send_keepdata( con->source, buf, size );
764    }
765}
766
767static TrTorrent *
768findtorhash( TrCore * core, const char * hash, int * torid )
769{
770    GtkTreeModel * model;
771    GtkTreeIter    iter;
772    char         * rowhash;
773    TrTorrent    * tor;
774
775    model = tr_core_model( core );
776    if( gtk_tree_model_get_iter_first( model, &iter ) )
777    {
778        do
779        {
780            gtk_tree_model_get( model, &iter, MC_HASH, &rowhash, -1 );
781            if( 0 == strcmp( hash, rowhash ) )
782            {
783                gtk_tree_model_get( model, &iter, MC_ID, torid,
784                                    MC_TORRENT, &tor, -1 );
785                g_object_unref( tor );
786                return tor;
787            }
788        }
789        while( gtk_tree_model_iter_next( model, &iter ) );
790    }
791
792    return NULL;
793}
794
795static void
796smsg_look( enum ipc_msg id UNUSED, benc_val_t * val, int64_t tag,
797             void * arg )
798{
799    struct constate      * con = arg;
800    struct constate_serv * srv = &con->u.serv;
801    benc_val_t             packet, * pkval, * hash;
802    int                    ii, torid;
803    TrTorrent            * tor;
804    const tr_info        * inf;
805    uint8_t              * buf;
806    size_t                 size;
807
808    if( NULL == val || TYPE_LIST != val->type )
809    {
810        simpleresp( con, tag, IPC_MSG_BAD );
811        return;
812    }
813
814    pkval = ipc_initval( con->ipc, IPC_MSG_INFO, tag, &packet, TYPE_LIST );
815    if( NULL == pkval )
816    {
817        simpleresp( con, tag, IPC_MSG_FAIL );
818        return;
819    }
820
821    for( ii = 0; val->val.l.count > ii; ii++ )
822    {
823        hash = &val->val.l.vals[ii];
824        if( NULL == hash || TYPE_STR != hash->type ||
825            SHA_DIGEST_LENGTH * 2 != hash->val.s.i ||
826            NULL == ( tor = findtorhash( srv->core, hash->val.s.s, &torid ) ) )
827        {
828            continue;
829        }
830        inf = tr_torrent_info( tor );
831        if( 0 > ipc_addinfo( pkval, torid, inf, IPC_INF_HASH ) )
832        {
833            tr_bencFree( &packet );
834            simpleresp( con, tag, IPC_MSG_FAIL );
835            return;
836        }
837    }
838
839    buf = ipc_mkval( &packet, &size );
840    tr_bencFree( &packet );
841    if( NULL == buf )
842    {
843        simpleresp( con, tag, IPC_MSG_FAIL );
844    }
845    else
846    {
847        io_send_keepdata( con->source, buf, size );
848    }
849}
850
851static void
852smsg_tor( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg )
853{
854    struct constate      * con = arg;
855    struct constate_serv * srv = &con->u.serv;
856    benc_val_t           * idval;
857    TrTorrent            * tor;
858    GtkTreeIter            iter;
859    int                    ii;
860
861    if( NULL == val || TYPE_LIST != val->type )
862    {
863        simpleresp( con, tag, IPC_MSG_BAD );
864        return;
865    }
866
867    for( ii = 0; val->val.l.count > ii; ii++ )
868    {
869        idval = &val->val.l.vals[ii];
870        if( TYPE_INT != idval->type || !TORRENT_ID_VALID( idval->val.i ) ||
871            NULL == ( tor = findtorid( srv->core, idval->val.i, &iter ) ) )
872        {
873            continue;
874        }
875        switch( id )
876        {
877            case IPC_MSG_REMOVE:
878                tr_core_delete_torrent( srv->core, &iter );
879                break;
880            case IPC_MSG_START:
881                tr_torrent_start( tor );
882                break;
883            case IPC_MSG_STOP:
884                tr_torrent_stop( tor );
885                break;
886            default:
887                g_assert_not_reached();
888                break;
889        }
890    }
891
892    tr_core_update( srv->core );
893
894    /* XXX this is a lie */
895    simpleresp( con, tag, IPC_MSG_OK );
896}
897
898static void
899smsg_torall( enum ipc_msg id, benc_val_t * val UNUSED, int64_t tag,
900             void * arg )
901{
902    struct constate      * con = arg;
903    struct constate_serv * srv = &con->u.serv;
904    TrTorrent            * tor;
905    GtkTreeModel         * model;
906    GtkTreeIter            iter;
907
908    model = tr_core_model( srv->core );
909    if( gtk_tree_model_get_iter_first( model, &iter ) )
910    {
911        do
912        {
913            gtk_tree_model_get( model, &iter, MC_TORRENT, &tor, -1 );
914            switch( id )
915            {
916                case IPC_MSG_REMOVEALL:
917                    tr_core_delete_torrent( srv->core, &iter );
918                    break;
919                case IPC_MSG_STARTALL:
920                    tr_torrent_start( tor );
921                    break;
922                case IPC_MSG_STOPALL:
923                    tr_torrent_stop( tor );
924                    break;
925                default:
926                    g_assert_not_reached();
927                    break;
928            }
929            g_object_unref( tor );
930        }
931        while( gtk_tree_model_iter_next( model, &iter ) );
932    }
933
934    tr_core_update( srv->core );
935
936    /* XXX this is a lie */
937    simpleresp( con, tag, IPC_MSG_OK );
938}
939
940#define TR_NAT_TRAVERSAL_IS_DISABLED( st ) \
941    ( TR_NAT_TRAVERSAL_UNMAPPED == (st) || TR_NAT_TRAVERSAL_UNMAPPING == (st) )
942
943static void
944smsg_pref( enum ipc_msg id, benc_val_t * val UNUSED, int64_t tag, void * arg )
945{
946    struct constate         * con = arg;
947    struct constate_serv    * srv = &con->u.serv;
948    uint8_t                 * buf;
949    size_t                    size;
950    const tr_handle_status  * hstat;
951    const char              * pref;
952    int                       num;
953
954    switch( id )
955    {
956        case IPC_MSG_GETAUTOMAP:
957            hstat = tr_handleStatus( tr_core_handle( srv->core ) );
958            buf = ipc_mkint( con->ipc, &size, IPC_MSG_AUTOMAP, tag,
959                             !TR_NAT_TRAVERSAL_IS_DISABLED(
960                                 hstat->natTraversalStatus ) );
961            break;
962        case IPC_MSG_GETAUTOSTART:
963            buf = ipc_mkint( con->ipc, &size, IPC_MSG_AUTOSTART, tag, 1 );
964            break;
965        case IPC_MSG_GETDIR:
966            /* XXX sending back "" when we're prompting is kind of bogus */
967            pref = pref_flag_get( PREF_KEY_OPTIONS_PROMPT ) ? "" : getdownloaddir();
968            buf = ipc_mkstr( con->ipc, &size, IPC_MSG_DIR, tag, pref );
969            break;
970        case IPC_MSG_GETDOWNLIMIT:
971            num = pref_flag_get( PREF_KEY_DL_LIMIT_ENABLED )
972                ? pref_int_get( PREF_KEY_DL_LIMIT )
973                : -1;
974            buf = ipc_mkint( con->ipc, &size, IPC_MSG_DOWNLIMIT, tag, num );
975            break;
976        case IPC_MSG_GETPEX:
977            buf = ipc_mkint( con->ipc, &size, IPC_MSG_PEX, tag,
978                             pref_flag_get( PREF_KEY_PEX ) );
979            break;
980        case IPC_MSG_GETPORT:
981            buf = ipc_mkint( con->ipc, &size, IPC_MSG_PORT, tag,
982                             pref_flag_get( PREF_KEY_PORT ) );
983            break;
984        case IPC_MSG_GETUPLIMIT:
985            num = pref_flag_get( PREF_KEY_UL_LIMIT_ENABLED )
986                ? pref_int_get( PREF_KEY_UL_LIMIT )
987                : -1;
988            buf = ipc_mkint( con->ipc, &size, IPC_MSG_UPLIMIT, tag, num );
989            break;
990        default:
991            g_assert_not_reached();
992            return;
993    }
994
995    if( NULL != buf )
996    {
997        io_send_keepdata( con->source, buf, size );
998    }
999}
1000
1001static void
1002smsg_int( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg )
1003{
1004    struct constate      * con = arg;
1005    struct constate_serv * srv = &con->u.serv;
1006
1007    if( NULL == val || TYPE_INT != val->type || INT_MAX < val->val.i )
1008    {
1009        simpleresp( con, tag, IPC_MSG_BAD );
1010        return;
1011    }
1012
1013    switch( id )
1014    {
1015        case IPC_MSG_AUTOMAP:
1016            tr_core_set_pref_bool( srv->core, PREF_KEY_NAT, val->val.i );
1017            break;
1018        case IPC_MSG_AUTOSTART:
1019            simpleresp( con, tag, IPC_MSG_BAD );
1020            return;
1021        case IPC_MSG_DOWNLIMIT:
1022            if( 0 > val->val.i )
1023            {
1024                tr_core_set_pref_bool( srv->core, PREF_KEY_DL_LIMIT_ENABLED, 0 );
1025            }
1026            else
1027            {
1028                tr_core_set_pref_int( srv->core, PREF_KEY_DL_LIMIT, val->val.i );
1029                tr_core_set_pref_bool( srv->core, PREF_KEY_DL_LIMIT_ENABLED, 1 );
1030            }
1031            break;
1032        case IPC_MSG_PEX:
1033            tr_core_set_pref_bool( srv->core, PREF_KEY_PEX, val->val.i );
1034            break;
1035        case IPC_MSG_PORT:
1036            tr_core_set_pref_int( srv->core, PREF_KEY_PORT, val->val.i );
1037            break;
1038        case IPC_MSG_UPLIMIT:
1039            if( 0 > val->val.i )
1040            {
1041                tr_core_set_pref_bool( srv->core, PREF_KEY_UL_LIMIT_ENABLED, 0 );
1042            }
1043            else
1044            {
1045                tr_core_set_pref_int( srv->core, PREF_KEY_UL_LIMIT, val->val.i );
1046                tr_core_set_pref_bool( srv->core, PREF_KEY_UL_LIMIT_ENABLED, 1 );
1047            }
1048            break;
1049        default:
1050            g_assert_not_reached();
1051            return;
1052    }
1053}
1054
1055static void
1056smsg_str( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg )
1057{
1058    struct constate      * con = arg;
1059    struct constate_serv * srv = &con->u.serv;
1060
1061    if( NULL == val || TYPE_STR != val->type )
1062    {
1063        simpleresp( con, tag, IPC_MSG_BAD );
1064        return;
1065    }
1066
1067    switch( id )
1068    {
1069        case IPC_MSG_DIR:
1070            tr_core_set_pref( srv->core, PREF_KEY_DIR_DEFAULT, val->val.s.s );
1071            break;
1072        default:
1073            g_assert_not_reached();
1074            return;
1075    }
1076}
1077
1078static void
1079smsg_sup( enum ipc_msg id UNUSED, benc_val_t * val, int64_t tag, void * arg )
1080{
1081    struct constate      * con = arg;
1082    benc_val_t             packet, * pkval, * name;
1083    int                    ii;
1084    enum ipc_msg           found;
1085    uint8_t              * buf;
1086    size_t                 size;
1087
1088    if( NULL == val || TYPE_LIST != val->type )
1089    {
1090        simpleresp( con, tag, IPC_MSG_BAD );
1091        return;
1092    }
1093
1094    pkval = ipc_initval( con->ipc, IPC_MSG_SUP, tag, &packet, TYPE_LIST );
1095    if( NULL == pkval )
1096    {
1097        simpleresp( con, tag, IPC_MSG_FAIL );
1098        return;
1099    }
1100    if( tr_bencListReserve( pkval, val->val.l.count ) )
1101    {
1102        tr_bencFree( &packet );
1103        simpleresp( con, tag, IPC_MSG_FAIL );
1104        return;
1105    }
1106
1107    for( ii = 0; val->val.l.count > ii; ii++ )
1108    {
1109        name = &val->val.l.vals[ii];
1110        if( NULL == name || TYPE_STR != name->type )
1111        {
1112            continue;
1113        }
1114        found = ipc_msgid( con->ipc, name->val.s.s );
1115        if( IPC__MSG_COUNT == found || !ipc_ishandled( con->ipc, found ) )
1116        {
1117            continue;
1118        }
1119        tr_bencInitStr( tr_bencListAdd( pkval ),
1120                        name->val.s.s, name->val.s.i, 1 );
1121    }
1122
1123    buf = ipc_mkval( &packet, &size );
1124    tr_bencFree( &packet );
1125    if( NULL == buf )
1126    {
1127        simpleresp( con, tag, IPC_MSG_FAIL );
1128    }
1129    else
1130    {
1131        io_send_keepdata( con->source, buf, size );
1132    }
1133}
1134
1135void
1136ipc_socket_setup( GtkWindow * parent, TrCore * core )
1137{
1138  struct constate *con;
1139
1140  con = g_new0(struct constate, 1);
1141  con->source = NULL;
1142  con->fd = -1;
1143  con->type = CON_SERV;
1144
1145  con->msgs = ipc_initmsgs();
1146  if( NULL == con->msgs ||
1147      0 > ipc_addmsg( con->msgs, IPC_MSG_ADDMANYFILES, smsg_add ) ||
1148      0 > ipc_addmsg( con->msgs, IPC_MSG_ADDONEFILE,   smsg_addone ) ||
1149      0 > ipc_addmsg( con->msgs, IPC_MSG_AUTOMAP,      smsg_int ) ||
1150      0 > ipc_addmsg( con->msgs, IPC_MSG_AUTOSTART,    smsg_int ) ||
1151      0 > ipc_addmsg( con->msgs, IPC_MSG_DIR,          smsg_str ) ||
1152      0 > ipc_addmsg( con->msgs, IPC_MSG_DOWNLIMIT,    smsg_int ) ||
1153      0 > ipc_addmsg( con->msgs, IPC_MSG_GETAUTOMAP,   smsg_pref ) ||
1154      0 > ipc_addmsg( con->msgs, IPC_MSG_GETAUTOSTART, smsg_pref ) ||
1155      0 > ipc_addmsg( con->msgs, IPC_MSG_GETDIR,       smsg_pref ) ||
1156      0 > ipc_addmsg( con->msgs, IPC_MSG_GETDOWNLIMIT, smsg_pref ) ||
1157      0 > ipc_addmsg( con->msgs, IPC_MSG_GETINFO,      smsg_info ) ||
1158      0 > ipc_addmsg( con->msgs, IPC_MSG_GETINFOALL,   smsg_infoall ) ||
1159      0 > ipc_addmsg( con->msgs, IPC_MSG_GETPEX,       smsg_pref ) ||
1160      0 > ipc_addmsg( con->msgs, IPC_MSG_GETPORT,      smsg_pref ) ||
1161      0 > ipc_addmsg( con->msgs, IPC_MSG_GETSTAT,      smsg_info ) ||
1162      0 > ipc_addmsg( con->msgs, IPC_MSG_GETSTATALL,   smsg_infoall ) ||
1163      0 > ipc_addmsg( con->msgs, IPC_MSG_GETUPLIMIT,   smsg_pref ) ||
1164      0 > ipc_addmsg( con->msgs, IPC_MSG_LOOKUP,       smsg_look ) ||
1165      0 > ipc_addmsg( con->msgs, IPC_MSG_NOOP,         smsg_noop ) ||
1166      0 > ipc_addmsg( con->msgs, IPC_MSG_PEX,          smsg_int ) ||
1167      0 > ipc_addmsg( con->msgs, IPC_MSG_PORT,         smsg_int ) ||
1168      0 > ipc_addmsg( con->msgs, IPC_MSG_QUIT,         smsg_quit ) ||
1169      0 > ipc_addmsg( con->msgs, IPC_MSG_REMOVE,       smsg_tor ) ||
1170      0 > ipc_addmsg( con->msgs, IPC_MSG_REMOVEALL,    smsg_torall ) ||
1171      0 > ipc_addmsg( con->msgs, IPC_MSG_START,        smsg_tor ) ||
1172      0 > ipc_addmsg( con->msgs, IPC_MSG_STARTALL,     smsg_torall ) ||
1173      0 > ipc_addmsg( con->msgs, IPC_MSG_STOP,         smsg_tor ) ||
1174      0 > ipc_addmsg( con->msgs, IPC_MSG_STOPALL,      smsg_torall ) ||
1175      0 > ipc_addmsg( con->msgs, IPC_MSG_SUP,          smsg_sup ) ||
1176      0 > ipc_addmsg( con->msgs, IPC_MSG_UPLIMIT,      smsg_int ) )
1177  {
1178      errmsg( con->u.serv.wind, _("Failed to set up IPC: %s"),
1179              g_strerror( errno ) );
1180      g_free( con );
1181      return;
1182  }
1183
1184  ipc_setdefmsg( con->msgs, all_default );
1185
1186  con->u.serv.wind = parent;
1187  con->u.serv.core = core;
1188
1189  g_object_add_weak_pointer( G_OBJECT( core ), &con->u.serv.core );
1190
1191  serv_bind(con);
1192}
Note: See TracBrowser for help on using the repository browser.