source: trunk/gtk/ipc.c @ 2208

Last change on this file since 2208 was 2208, checked in by charles, 15 years ago

set a default window size for the debug window

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