Changeset 5125


Ignore:
Timestamp:
Feb 26, 2008, 9:05:13 PM (14 years ago)
Author:
charles
Message:

(gtk) group the ipc functions by call order

Location:
trunk/gtk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/gtk/ipc.c

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

    r5124 r5125  
    6161};
    6262
    63 static struct iosource *
    64 newsource(void);
    65 static void
    66 freeoutbuf(struct iooutbuf *buf);
    6763static gboolean
    68 io_prepare(GSource *source, gint *timeout_);
     64io_prepare(GSource *source UNUSED, gint *timeout_) {
     65  *timeout_ = -1;
     66  return FALSE;
     67}
     68
    6969static gboolean
    70 io_check(GSource *source);
     70io_check(GSource *source) {
     71  struct iosource *io = (struct iosource*)source;
     72
     73  if(io->infd.revents)
     74    return TRUE;
     75  if(NULL != io->outbufs && io->outfd.revents)
     76    return TRUE;
     77  else
     78    return FALSE;
     79}
     80
     81static void
     82io_disconnect(struct iosource *io, int err) {
     83  if(NULL != io->closed) {
     84    errno = err;
     85    io->closed((GSource*)io, io->cbdata);
     86  }
     87
     88  if(NULL != io->outbufs)
     89    g_source_remove_poll((GSource*)io, &io->outfd);
     90
     91  g_source_remove_poll((GSource*)io, &io->infd);
     92  g_source_remove(g_source_get_id((GSource*)io));
     93  g_source_unref((GSource*)io);
     94}
     95
     96static void
     97io_biggify(char **buf, size_t used, size_t *max) {
     98  if(used + IO_BLOCKSIZE > *max) {
     99    *max += IO_BLOCKSIZE;
     100    *buf = g_renew(char, *buf, *max);
     101  }
     102}
     103
     104static void
     105io_read(struct iosource *io) {
     106  ssize_t res = 0;
     107  gboolean newdata = FALSE;
     108  size_t used;
     109  int err = 0;
     110
     111  g_source_ref((GSource*)io);
     112
     113  do {
     114    if(!newdata && 0 < res)
     115      newdata = TRUE;
     116    io->inused += res;
     117    io_biggify(&io->inbuf, io->inused, &io->inmax);
     118    errno = 0;
     119    res = read(io->infd.fd, io->inbuf + io->inused, io->inmax - io->inused);
     120    if(0 > res)
     121      err = errno;
     122  } while(0 < res);
     123
     124  if(NULL == io->received)
     125    io->inused = 0;
     126  else if(newdata) {
     127    used = io->received((GSource*)io, io->inbuf, io->inused, io->cbdata);
     128    if(used > io->inused)
     129      used = io->inused;
     130    if(0 < used) {
     131      if(used < io->inused)
     132        memmove(io->inbuf, io->inbuf + used, io->inused - used);
     133      io->inused -= used;
     134    }
     135  }
     136
     137  if(0 != err && EAGAIN != err)
     138    io_disconnect(io, err);
     139  else if(0 == res)
     140    io_disconnect(io, 0);
     141  g_source_unref((GSource*)io);
     142}
     143
     144static void
     145io_accept(struct iosource *io) {
     146  int fd;
     147  socklen_t len;
     148
     149  len = io->inmax;
     150  if(0 > (fd = accept(io->infd.fd, (struct sockaddr*)io->inbuf, &len))) {
     151    if(EAGAIN == errno || ECONNABORTED == errno || EWOULDBLOCK == errno)
     152      return;
     153    io_disconnect(io, errno);
     154  }
     155
     156  io->accepted((GSource*)io, fd, (struct sockaddr*)io->inbuf, len, io->cbdata);
     157}
     158
     159static void
     160freeoutbuf(struct iooutbuf *buf) {
     161  if(NULL != buf->data)
     162    g_free(buf->data);
     163  g_free(buf);
     164}
     165
     166static void
     167io_write(struct iosource *io) {
     168  struct iooutbuf *buf;
     169  ssize_t res = 1;
     170  int err = 0;
     171
     172  g_source_ref((GSource*)io);
     173
     174  while(NULL != io->outbufs && 0 == err) {
     175    buf = io->outbufs->data;
     176    while(buf->off < buf->len && 0 < res) {
     177      errno = 0;
     178      res = write(io->outfd.fd, buf->data + buf->off, buf->len - buf->off);
     179      if(0 > res)
     180        err = errno;
     181      else
     182        buf->off += res;
     183    }
     184
     185    if(buf->off >= buf->len) {
     186      io->outbufs = g_list_remove(io->outbufs, buf);
     187      if(NULL == io->outbufs)
     188        g_source_remove_poll((GSource*)io, &io->outfd);
     189      if(NULL != io->sent)
     190        io->sent((GSource*)io, buf->id, io->cbdata);
     191      freeoutbuf(buf);
     192    }
     193  }
     194
     195  if(0 != err && EAGAIN != err)
     196    io_disconnect(io, err);
     197
     198  g_source_unref((GSource*)io);
     199}
     200
    71201static gboolean
    72 io_dispatch(GSource *source, GSourceFunc callback, gpointer gdata);
    73 static void
    74 io_finalize(GSource *source);
    75 static void
    76 io_accept(struct iosource *io);
    77 static void
    78 io_read(struct iosource *io);
    79 static void
    80 io_write(struct iosource *io);
    81 static void
    82 io_disconnect(struct iosource *io, int err);
     202io_dispatch(GSource *source, GSourceFunc callback UNUSED,
     203            gpointer gdata UNUSED) {
     204  struct iosource *io = (struct iosource*)source;
     205
     206  if(io->infd.revents & (G_IO_ERR | G_IO_HUP) ||
     207     io->outfd.revents & G_IO_ERR)
     208    io_disconnect(io, 0 /* XXX how do I get errors here? */ );
     209  else if(io->infd.revents & G_IO_IN)
     210    (NULL == io->accepted ? io_read : io_accept)(io);
     211  else if(io->outfd.revents & G_IO_OUT)
     212    io_write(io);
     213  else
     214    return FALSE;
     215
     216  return TRUE;
     217}
     218
     219static void
     220io_finalize(GSource *source UNUSED) {
     221  struct iosource *io = (struct iosource*)source;
     222
     223  if(NULL != io->outbufs) {
     224    g_list_foreach(io->outbufs, (GFunc)freeoutbuf, NULL);
     225    g_list_free(io->outbufs);
     226  }
     227
     228  if(NULL != io->inbuf)
     229    g_free(io->inbuf);
     230}
    83231
    84232static GSourceFuncs sourcefuncs = {
     
    90238  NULL
    91239};
    92 
    93 static int
    94 nonblock(int fd)
    95 {
    96     const int err = evutil_make_socket_nonblocking( fd );
    97     return err;
    98 }
    99 
    100 GSource *
    101 io_new(int fd, ioidfunc_t sent, iodatafunc_t received,
    102        iofunc_t closed, void *cbdata) {
    103   struct iosource *io;
    104 
    105   if( nonblock( fd ) )
    106     return NULL;
    107 
    108   io = newsource();
    109   io->sent = sent;
    110   io->received = received;
    111   io->closed = closed;
    112   io->cbdata = cbdata;
    113   io->infd.fd = fd;
    114   io->infd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
    115   io->infd.revents = 0;
    116   io->outfd.fd = fd;
    117   io->outfd.events = G_IO_OUT | G_IO_ERR;
    118   io->outfd.revents = 0;
    119 
    120   g_source_add_poll((GSource*)io, &io->infd);
    121   g_source_attach((GSource*)io, NULL);
    122 
    123   return (GSource*)io;
    124 }
    125 
    126 GSource *
    127 io_new_listening(int fd, socklen_t len, ionewfunc_t accepted,
    128                  iofunc_t closed, void *cbdata) {
    129   struct iosource *io;
    130 
    131   g_assert(NULL != accepted);
    132 
    133   if( nonblock( fd ) )
    134     return NULL;
    135 
    136   io = newsource();
    137   io->accepted = accepted;
    138   io->closed = closed;
    139   io->cbdata = cbdata;
    140   io->infd.fd = fd;
    141   io->infd.events = G_IO_IN | G_IO_ERR;
    142   io->infd.revents = 0;
    143   io->inbuf = g_new(char, len);
    144   io->inmax = len;
    145 
    146   g_source_add_poll((GSource*)io, &io->infd);
    147   g_source_attach((GSource*)io, NULL);
    148 
    149   return (GSource*)io;
    150 }
    151240
    152241static struct iosource *
     
    173262}
    174263
     264GSource *
     265io_new(int fd, ioidfunc_t sent, iodatafunc_t received,
     266       iofunc_t closed, void *cbdata) {
     267  struct iosource *io;
     268
     269  if( evutil_make_socket_nonblocking( fd ) )
     270    return NULL;
     271
     272  io = newsource();
     273  io->sent = sent;
     274  io->received = received;
     275  io->closed = closed;
     276  io->cbdata = cbdata;
     277  io->infd.fd = fd;
     278  io->infd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
     279  io->infd.revents = 0;
     280  io->outfd.fd = fd;
     281  io->outfd.events = G_IO_OUT | G_IO_ERR;
     282  io->outfd.revents = 0;
     283
     284  g_source_add_poll((GSource*)io, &io->infd);
     285  g_source_attach((GSource*)io, NULL);
     286
     287  return (GSource*)io;
     288}
     289
     290GSource *
     291io_new_listening(int fd, socklen_t len, ionewfunc_t accepted,
     292                 iofunc_t closed, void *cbdata) {
     293  struct iosource *io;
     294
     295  g_assert(NULL != accepted);
     296
     297  if( evutil_make_socket_nonblocking( fd ) )
     298    return NULL;
     299
     300  io = newsource();
     301  io->accepted = accepted;
     302  io->closed = closed;
     303  io->cbdata = cbdata;
     304  io->infd.fd = fd;
     305  io->infd.events = G_IO_IN | G_IO_ERR;
     306  io->infd.revents = 0;
     307  io->inbuf = g_new(char, len);
     308  io->inmax = len;
     309
     310  g_source_add_poll((GSource*)io, &io->infd);
     311  g_source_attach((GSource*)io, NULL);
     312
     313  return (GSource*)io;
     314}
     315
    175316unsigned int
    176317io_send_keepdata(GSource *source, void *data, size_t len) {
     
    193334  return io->lastid;
    194335}
    195 
    196 static void
    197 freeoutbuf(struct iooutbuf *buf) {
    198   if(NULL != buf->data)
    199     g_free(buf->data);
    200   g_free(buf);
    201 }
    202 
    203 static gboolean
    204 io_prepare(GSource *source UNUSED, gint *timeout_) {
    205   *timeout_ = -1;
    206   return FALSE;
    207 }
    208 
    209 static gboolean
    210 io_check(GSource *source) {
    211   struct iosource *io = (struct iosource*)source;
    212 
    213   if(io->infd.revents)
    214     return TRUE;
    215   if(NULL != io->outbufs && io->outfd.revents)
    216     return TRUE;
    217   else
    218     return FALSE;
    219 }
    220 
    221 static gboolean
    222 io_dispatch(GSource *source, GSourceFunc callback UNUSED,
    223             gpointer gdata UNUSED) {
    224   struct iosource *io = (struct iosource*)source;
    225 
    226   if(io->infd.revents & (G_IO_ERR | G_IO_HUP) ||
    227      io->outfd.revents & G_IO_ERR)
    228     io_disconnect(io, 0 /* XXX how do I get errors here? */ );
    229   else if(io->infd.revents & G_IO_IN)
    230     (NULL == io->accepted ? io_read : io_accept)(io);
    231   else if(io->outfd.revents & G_IO_OUT)
    232     io_write(io);
    233   else
    234     return FALSE;
    235 
    236   return TRUE;
    237 }
    238 
    239 
    240 static void
    241 io_finalize(GSource *source UNUSED) {
    242   struct iosource *io = (struct iosource*)source;
    243 
    244   if(NULL != io->outbufs) {
    245     g_list_foreach(io->outbufs, (GFunc)freeoutbuf, NULL);
    246     g_list_free(io->outbufs);
    247   }
    248 
    249   if(NULL != io->inbuf)
    250     g_free(io->inbuf);
    251 }
    252 
    253 static void
    254 io_biggify(char **buf, size_t used, size_t *max) {
    255   if(used + IO_BLOCKSIZE > *max) {
    256     *max += IO_BLOCKSIZE;
    257     *buf = g_renew(char, *buf, *max);
    258   }
    259 }
    260 
    261 static void
    262 io_accept(struct iosource *io) {
    263   int fd;
    264   socklen_t len;
    265 
    266   len = io->inmax;
    267   if(0 > (fd = accept(io->infd.fd, (struct sockaddr*)io->inbuf, &len))) {
    268     if(EAGAIN == errno || ECONNABORTED == errno || EWOULDBLOCK == errno)
    269       return;
    270     io_disconnect(io, errno);
    271   }
    272 
    273   io->accepted((GSource*)io, fd, (struct sockaddr*)io->inbuf, len, io->cbdata);
    274 }
    275 
    276 static void
    277 io_read(struct iosource *io) {
    278   ssize_t res = 0;
    279   gboolean newdata = FALSE;
    280   size_t used;
    281   int err = 0;
    282 
    283   g_source_ref((GSource*)io);
    284 
    285   do {
    286     if(!newdata && 0 < res)
    287       newdata = TRUE;
    288     io->inused += res;
    289     io_biggify(&io->inbuf, io->inused, &io->inmax);
    290     errno = 0;
    291     res = read(io->infd.fd, io->inbuf + io->inused, io->inmax - io->inused);
    292     if(0 > res)
    293       err = errno;
    294   } while(0 < res);
    295 
    296   if(NULL == io->received)
    297     io->inused = 0;
    298   else if(newdata) {
    299     used = io->received((GSource*)io, io->inbuf, io->inused, io->cbdata);
    300     if(used > io->inused)
    301       used = io->inused;
    302     if(0 < used) {
    303       if(used < io->inused)
    304         memmove(io->inbuf, io->inbuf + used, io->inused - used);
    305       io->inused -= used;
    306     }
    307   }
    308 
    309   if(0 != err && EAGAIN != err)
    310     io_disconnect(io, err);
    311   else if(0 == res)
    312     io_disconnect(io, 0);
    313   g_source_unref((GSource*)io);
    314 }
    315 
    316 static void
    317 io_write(struct iosource *io) {
    318   struct iooutbuf *buf;
    319   ssize_t res = 1;
    320   int err = 0;
    321 
    322   g_source_ref((GSource*)io);
    323 
    324   while(NULL != io->outbufs && 0 == err) {
    325     buf = io->outbufs->data;
    326     while(buf->off < buf->len && 0 < res) {
    327       errno = 0;
    328       res = write(io->outfd.fd, buf->data + buf->off, buf->len - buf->off);
    329       if(0 > res)
    330         err = errno;
    331       else
    332         buf->off += res;
    333     }
    334 
    335     if(buf->off >= buf->len) {
    336       io->outbufs = g_list_remove(io->outbufs, buf);
    337       if(NULL == io->outbufs)
    338         g_source_remove_poll((GSource*)io, &io->outfd);
    339       if(NULL != io->sent)
    340         io->sent((GSource*)io, buf->id, io->cbdata);
    341       freeoutbuf(buf);
    342     }
    343   }
    344 
    345   if(0 != err && EAGAIN != err)
    346     io_disconnect(io, err);
    347 
    348   g_source_unref((GSource*)io);
    349 }
    350 
    351 static void
    352 io_disconnect(struct iosource *io, int err) {
    353   if(NULL != io->closed) {
    354     errno = err;
    355     io->closed((GSource*)io, io->cbdata);
    356   }
    357 
    358   if(NULL != io->outbufs)
    359     g_source_remove_poll((GSource*)io, &io->outfd);
    360 
    361   g_source_remove_poll((GSource*)io, &io->infd);
    362   g_source_remove(g_source_get_id((GSource*)io));
    363   g_source_unref((GSource*)io);
    364 }
Note: See TracChangeset for help on using the changeset viewer.