source: trunk/libtransmission/rpc.c @ 5827

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

make the request/response messages a little terser. add per-torrent speed limit toggles. rename ipc -> rpc.

File size: 20.8 KB
Line 
1/*
2 * This file Copyright (C) 2008 Charles Kerr <charles@rebelbase.com>
3 *
4 * This file is licensed by the GPL version 2.  Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
9 *
10 * $Id:$
11 */
12
13#include <assert.h>
14#include <string.h> /* strcmp */
15
16#include "transmission.h"
17#include "bencode.h"
18#include "rpc.h"
19#include "torrent.h"
20#include "utils.h"
21
22#define TR_N_ELEMENTS( ary ) ( sizeof( ary ) / sizeof( (ary)[0] ) )
23
24/***
25****
26***/
27
28static tr_torrent **
29getTorrents( tr_handle * handle, tr_benc * args, int * setmeCount )
30{
31    tr_torrent ** torrents = NULL;
32    int torrentCount = 0;
33    tr_benc * ids;
34
35    if( tr_bencDictFindList( args, "ids", &ids ) )
36    {
37        int i;
38        const int n = tr_bencListSize( ids );
39
40        torrents = tr_new0( tr_torrent*, n );
41
42        for( i=0; i<n; ++i )
43        {
44            tr_torrent * tor = NULL;
45            tr_benc * node = tr_bencListChild( ids, i );
46            int64_t id;
47            const char * str;
48            if( tr_bencGetInt( node, &id ) )
49                tor = tr_torrentFindFromId( handle, id );
50            else if( tr_bencGetStr( node, &str ) )
51                tor = tr_torrentFindFromHashString( handle, str );
52            if( tor )
53                torrents[torrentCount++] = tor;
54        }
55    }
56    else /* all of them */
57    {
58        tr_torrent * tor = NULL;
59        const int n = tr_torrentCount( handle );
60        torrents = tr_new0( tr_torrent*, n );
61        while(( tor = tr_torrentNext( handle, tor )))
62            torrents[torrentCount++] = tor;
63    }
64
65    *setmeCount = torrentCount;
66    return torrents;
67}
68
69typedef void( *tor_func )( tr_torrent * tor );
70
71static void callTorrentFunc( tr_handle * h, tr_benc * args_in, tor_func func )
72{
73    int i, torrentCount;
74    tr_torrent ** torrents = getTorrents( h, args_in, &torrentCount );
75    for( i=0; i<torrentCount; ++i )
76        ( *func )( torrents[i] );
77    tr_free( torrents );
78}
79
80static const char*
81torrentStart( tr_handle * h, tr_benc * args_in, tr_benc * args_out UNUSED )
82{
83    callTorrentFunc( h, args_in, tr_torrentStart );
84    return NULL;
85}
86
87static const char*
88torrentStop( tr_handle * h, tr_benc * args_in, tr_benc * args_out UNUSED )
89{
90    callTorrentFunc( h, args_in, tr_torrentStop );
91    return NULL;
92}
93
94static const char*
95torrentClose( tr_handle * h, tr_benc * args_in, tr_benc * args_out UNUSED )
96{
97    callTorrentFunc( h, args_in, tr_torrentClose );
98    return NULL;
99}
100
101static const char*
102torrentVerify( tr_handle * h, tr_benc * args_in, tr_benc * args_out UNUSED )
103{
104    callTorrentFunc( h, args_in, tr_torrentVerify );
105    return NULL;
106}
107
108static const char*
109torrentStatus( tr_handle * handle, tr_benc * args_in, tr_benc * args_out )
110{
111    int i, torrentCount;
112    tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
113    tr_benc * list = tr_bencDictAddList( args_out, "status", torrentCount );
114
115    for( i=0; i<torrentCount; ++i )
116    {
117        tr_torrent * tor = torrents[i];
118        const tr_stat * st = tr_torrentStat( tor );
119        tr_benc * d = tr_bencListAddDict( list, 32 );
120        tr_benc * t;
121        const int * f = st->peersFrom;
122        const struct tr_tracker_stat * s = &st->tracker_stat;
123
124        tr_bencDictAddInt( d, "id", tor->uniqueId );
125        tr_bencDictAddInt( d, "status", st->status );
126        tr_bencDictAddInt( d, "error", st->error );
127        tr_bencDictAddStr( d, "errorString", st->errorString );
128        tr_bencDictAddDouble( d, "recheckProgress", st->recheckProgress );
129        tr_bencDictAddDouble( d, "percentComplete", st->percentComplete );
130        tr_bencDictAddDouble( d, "percentDone", st->percentDone );
131        tr_bencDictAddDouble( d, "rateDownload", st->rateDownload );
132        tr_bencDictAddDouble( d, "rateUpload", st->rateUpload );
133        tr_bencDictAddDouble( d, "swarmspeed", st->swarmspeed );
134        tr_bencDictAddDouble( d, "ratio", st->ratio );
135        tr_bencDictAddInt( d, "eta", st->eta );
136        tr_bencDictAddInt( d, "peersKnown", st->peersKnown );
137        tr_bencDictAddInt( d, "peersConnected", st->peersConnected );
138        tr_bencDictAddInt( d, "peersSendingToUs", st->peersSendingToUs );
139        tr_bencDictAddInt( d, "peersGettingFromUs", st->peersGettingFromUs );
140        tr_bencDictAddInt( d, "seeders", st->seeders );
141        tr_bencDictAddInt( d, "leechers", st->leechers );
142        tr_bencDictAddInt( d, "completedFromTracker", st->completedFromTracker );
143        tr_bencDictAddInt( d, "manualAnnounceTime", st->manualAnnounceTime );
144        tr_bencDictAddInt( d, "sizeWhenDone", st->sizeWhenDone );
145        tr_bencDictAddInt( d, "leftUntilDone", st->leftUntilDone );
146        tr_bencDictAddInt( d, "desiredAvailable", st->desiredAvailable );
147        tr_bencDictAddInt( d, "corruptEver", st->corruptEver );
148        tr_bencDictAddInt( d, "uploadedEver", st->uploadedEver );
149        tr_bencDictAddInt( d, "downloadedEver", st->downloadedEver );
150        tr_bencDictAddInt( d, "haveValid", st->haveValid );
151        tr_bencDictAddInt( d, "haveUnchecked", st->haveUnchecked );
152        tr_bencDictAddInt( d, "startDate", st->startDate );
153        tr_bencDictAddInt( d, "activityDate", st->activityDate );
154        t = tr_bencDictAddDict( d, "peersFrom", 4 );
155            tr_bencDictAddInt( t, "cache",    f[TR_PEER_FROM_CACHE] );
156            tr_bencDictAddInt( t, "incoming", f[TR_PEER_FROM_INCOMING] );
157            tr_bencDictAddInt( t, "pex",      f[TR_PEER_FROM_PEX] );
158            tr_bencDictAddInt( t, "tracker",  f[TR_PEER_FROM_TRACKER] );
159        t = tr_bencDictAddDict( d, "tracker_stat", 7 );
160            tr_bencDictAddStr( t, "scrapeResponse", s->scrapeResponse );
161            tr_bencDictAddStr( t, "announceResponse", s->announceResponse );
162            tr_bencDictAddInt( t, "lastScrapeTime", s->lastScrapeTime );
163            tr_bencDictAddInt( t, "nextScrapeTime", s->nextScrapeTime );
164            tr_bencDictAddInt( t, "lastAnnounceTime", s->lastAnnounceTime );
165            tr_bencDictAddInt( t, "nextAnnounceTime", s->nextAnnounceTime );
166            tr_bencDictAddInt( t, "nextManualAnnounceTime", s->nextManualAnnounceTime );
167    }
168
169    /* cleanup */
170    tr_free( torrents );
171    return NULL;
172}
173
174static void
175addFiles( const tr_info * info, tr_benc * files )
176{
177    unsigned int i;
178    for( i=0; i<info->fileCount; ++i )
179    {
180        const tr_file * file = &info->files[i];
181        tr_benc * d = tr_bencListAddDict( files, 4 );
182        tr_bencDictAddInt( d, "length", file->length );
183        tr_bencDictAddStr( d, "name", file->name );
184        tr_bencDictAddInt( d, "priority", file->priority );
185        tr_bencDictAddInt( d, "dnd", file->dnd );
186    }
187}
188
189static void
190addTrackers( const tr_info * info, tr_benc * trackers )
191{
192    int i;
193    for( i=0; i<info->trackerCount; ++i )
194    {
195        const tr_tracker_info * t = &info->trackers[i];
196        tr_benc * d = tr_bencListAddDict( trackers, 3 );
197        tr_bencDictAddInt( d, "tier", t->tier );
198        tr_bencDictAddStr( d, "announce", t->announce );
199        tr_bencDictAddStr( d, "scrape", t->scrape );
200    }
201}
202
203static void
204serializeInfo( const tr_torrent * tor, tr_benc * d )
205{
206    const tr_info * inf = tr_torrentInfo( tor );
207    tr_bencInitDict( d, 14 ); 
208    tr_bencDictAddInt( d, "id", tor->uniqueId );
209    tr_bencDictAddStr( d, "torrent", inf->torrent );
210    tr_bencDictAddStr( d, "hashString", inf->hashString );
211    tr_bencDictAddStr( d, "name", inf->name );
212    tr_bencDictAddStr( d, "comment", inf->comment ? inf->comment : "" );
213    tr_bencDictAddStr( d, "creator", inf->creator ? inf->creator : "" );
214    tr_bencDictAddInt( d, "isPrivate", inf->isPrivate );
215    tr_bencDictAddInt( d, "isMultifile", inf->isMultifile );
216    tr_bencDictAddInt( d, "dateCreated", inf->dateCreated );
217    tr_bencDictAddInt( d, "pieceSize", inf->pieceSize );
218    tr_bencDictAddInt( d, "pieceCount", inf->pieceCount );
219    tr_bencDictAddInt( d, "totalSize", inf->totalSize );
220    addFiles   ( inf, tr_bencDictAddList( d, "files", inf->fileCount ) );
221    addTrackers( inf, tr_bencDictAddList( d, "files", inf->trackerCount ) );
222}
223
224static const char*
225torrentInfo( tr_handle * handle, tr_benc * args_in, tr_benc * args_out )
226{
227    int i, torrentCount;
228    tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
229    tr_benc * list = tr_bencDictAddList( args_out, "status", torrentCount );
230
231    for( i=0; i<torrentCount; ++i )
232        serializeInfo( torrents[i], tr_bencListAdd( list ) );
233
234    tr_free( torrents );
235    return NULL;
236}
237
238static const char*
239torrentGet( tr_handle * handle, tr_benc * args_in, tr_benc * args_out )
240{
241    int i, torrentCount;
242    tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
243    tr_benc * list = tr_bencDictAddList( args_out, "torrents", torrentCount );
244
245    for( i=0; i<torrentCount; ++i )
246    {
247        tr_torrent * tor = torrents[i];
248        tr_benc * d = tr_bencListAddDict( list, 6 );
249        tr_bencDictAddInt( d, "id", tor->uniqueId );
250        tr_bencDictAddInt( d, "peer-limit",
251                           tr_torrentGetPeerLimit( tor ) );
252        tr_bencDictAddInt( d, "speed-limit-down",
253                           tr_torrentGetSpeedLimit( tor, TR_DOWN ) );
254        tr_bencDictAddInt( d, "speed-limit-down-enabled",
255                           tr_torrentGetSpeedMode( tor, TR_DOWN )
256                               == TR_SPEEDLIMIT_SINGLE );
257        tr_bencDictAddInt( d, "speed-limit-up",
258                           tr_torrentGetSpeedLimit( tor, TR_UP ) );
259        tr_bencDictAddInt( d, "speed-limit-up-enabled",
260                           tr_torrentGetSpeedMode( tor, TR_UP )
261                               == TR_SPEEDLIMIT_SINGLE );
262    }
263
264    tr_free( torrents );
265    return NULL;
266}
267
268static const char*
269torrentSet( tr_handle * handle, tr_benc * args_in, tr_benc * args_out UNUSED )
270{
271    int i, torrentCount;
272    tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
273
274    for( i=0; i<torrentCount; ++i )
275    {
276        int64_t tmp;
277        tr_torrent * tor = torrents[i];
278        if( tr_bencDictFindInt( args_in, "peer-limit", &tmp ) )
279            tr_torrentSetPeerLimit( tor, tmp );
280        if( tr_bencDictFindInt( args_in, "speed-limit-down", &tmp ) )
281            tr_torrentSetSpeedLimit( tor, TR_DOWN, tmp );
282        if( tr_bencDictFindInt( args_in, "speed-limit-down-enabled", &tmp ) )
283            tr_torrentSetSpeedMode( tor, TR_DOWN, tmp ? TR_SPEEDLIMIT_SINGLE
284                                                      : TR_SPEEDLIMIT_GLOBAL );
285        if( tr_bencDictFindInt( args_in, "speed-limit-up", &tmp ) )
286            tr_torrentSetSpeedLimit( tor, TR_UP, tmp );
287        if( tr_bencDictFindInt( args_in, "speed-limit-up-enabled", &tmp ) )
288            tr_torrentSetSpeedMode( tor, TR_UP, tmp ? TR_SPEEDLIMIT_SINGLE
289                                                    : TR_SPEEDLIMIT_GLOBAL );
290    }
291
292    tr_free( torrents );
293    return NULL;
294}
295
296typedef int( *fileTestFunc )( const tr_torrent * tor, int i );
297
298static int
299testFileHigh( const tr_torrent * tor, int i )
300{
301    return tor->info.files[i].priority == TR_PRI_HIGH;
302}
303static int
304testFileLow( const tr_torrent * tor, int i )
305{
306    return tor->info.files[i].priority == TR_PRI_LOW;
307}
308static int
309testFileNormal( const tr_torrent * tor, int i )
310{
311    return tor->info.files[i].priority == TR_PRI_NORMAL;
312}
313static int
314testFileDND( const tr_torrent * tor, int i )
315{
316    return tor->info.files[i].dnd != 0;
317}
318static int
319testFileDownload( const tr_torrent * tor, int i )
320{
321    return tor->info.files[i].dnd == 0;
322}
323
324static void
325buildFileList( const tr_torrent * tor, tr_benc * dict,
326               const char * key, fileTestFunc func )
327{
328    int i;
329    const int n = tor->info.fileCount;
330    tr_benc * list;
331    int * files = tr_new0( int, n );
332    int fileCount = 0;
333   
334    for( i=0; i<n; ++i )
335        if( func( tor, i ) )
336            files[fileCount++] = i;
337
338    list = tr_bencDictAddList( dict, key, fileCount );
339
340    for( i=0; i<fileCount; ++i )
341        tr_bencListAddInt( list, files[i] );
342
343    tr_free( files );
344}
345
346static const char*
347torrentGetFile( tr_handle * handle, tr_benc * args_in, tr_benc * args_out )
348{
349    int i, torrentCount;
350    tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
351    tr_benc * list = tr_bencDictAddList( args_out, "torrents", torrentCount );
352
353    for( i=0; i<torrentCount; ++i )
354    {
355        const tr_torrent * tor = torrents[i];
356        tr_benc * d = tr_bencListAddDict( list, 6 );
357        tr_bencDictAddInt( d, "id", tor->uniqueId );
358        buildFileList( tor, d, "priority-high", testFileHigh );
359        buildFileList( tor, d, "priority-low", testFileLow );
360        buildFileList( tor, d, "priority-normal", testFileNormal );
361        buildFileList( tor, d, "download", testFileDownload );
362        buildFileList( tor, d, "no-download", testFileDND );
363    }
364
365    tr_free( torrents );
366    return NULL;
367}
368
369static void
370setFilePriorities( tr_torrent * tor, int priority, tr_benc * list )
371{
372    const int n = tr_bencListSize( list );
373    int i;
374    int64_t tmp;
375    int fileCount = 0;
376    tr_file_index_t * files = tr_new0( tr_file_index_t, n );
377
378    for( i=0; i<n; ++i )
379        if( tr_bencGetInt( tr_bencListChild(list,i), &tmp ) )
380            files[fileCount++] = tmp;
381
382    if( fileCount )
383        tr_torrentSetFilePriorities( tor, files, fileCount, priority );
384
385    tr_free( files );
386}
387
388static void
389setFileDLs( tr_torrent * tor, int do_download, tr_benc * list )
390{
391    const int n = tr_bencListSize( list );
392    int i;
393    int64_t tmp;
394    int fileCount = 0;
395    tr_file_index_t * files = tr_new0( tr_file_index_t, n );
396
397    for( i=0; i<n; ++i )
398        if( tr_bencGetInt( tr_bencListChild(list,i), &tmp ) )
399            files[fileCount++] = tmp;
400
401    if( fileCount )
402        tr_torrentSetFileDLs( tor, files, fileCount, do_download );
403
404    tr_free( files );
405}
406
407static const char*
408torrentSetFile( tr_handle * h, tr_benc * args_in, tr_benc * args_out UNUSED )
409{
410    int i, torrentCount;
411    tr_torrent ** torrents = getTorrents( h, args_in, &torrentCount );
412
413    for( i=0; i<torrentCount; ++i )
414    {
415        tr_benc * files;
416        tr_torrent * tor = torrents[i];
417
418        if( tr_bencDictFindList( args_in, "priority-high", &files ) )
419            setFilePriorities( tor, TR_PRI_HIGH, files );
420        if( tr_bencDictFindList( args_in, "priority-low", &files ) )
421            setFilePriorities( tor, TR_PRI_LOW, files );
422        if( tr_bencDictFindList( args_in, "priority-normal", &files ) )
423            setFilePriorities( tor, TR_PRI_NORMAL, files );
424        if( tr_bencDictFindList( args_in, "download", &files ) )
425            setFileDLs( tor, TRUE, files );
426        if( tr_bencDictFindList( args_in, "no-download", &files ) )
427            setFileDLs( tor, FALSE, files );
428    }
429
430    tr_free( torrents );
431    return NULL;
432}
433
434/***
435****
436***/
437
438static const char*
439torrentAdd( tr_handle * h, tr_benc * args_in, tr_benc * args_out )
440{
441    const char * filename;
442    if( !tr_bencDictFindStr( args_in, "filename", &filename ) )
443        return "no filename specified";
444    else {
445        int64_t i;
446        int err = 0;
447        const char * str;
448        tr_ctor * ctor;
449        tr_torrent * tor;
450
451        ctor = tr_ctorNew( h );
452        tr_ctorSetMetainfoFromFile( ctor, filename );
453        if( tr_bencDictFindInt( args_in, "paused", &i ) )
454            tr_ctorSetPaused( ctor, TR_FORCE, i );
455        if( tr_bencDictFindInt( args_in, "peer-limit", &i ) )
456            tr_ctorSetPeerLimit( ctor, TR_FORCE, i );
457        if( tr_bencDictFindStr( args_in, "destination", &str ) )
458            tr_ctorSetDestination( ctor, TR_FORCE, str );
459        tor = tr_torrentNew( h, ctor, &err );
460        tr_ctorFree( ctor );
461
462        if( tor )
463            serializeInfo( tor, tr_bencDictAdd( args_out, "torrent-added" ) );
464        else if( err == TR_EDUPLICATE )
465            return "duplicate torrent";
466        else if( err == TR_EINVALID )
467            return "invalid or corrupt torrent file";
468    }
469
470    return NULL;
471}
472
473/***
474****
475***/
476
477static const char*
478sessionSet( tr_handle * h, tr_benc * args_in, tr_benc * args_out UNUSED )
479{
480    int64_t i;
481    const char * str;
482
483    if( tr_bencDictFindInt( args_in, "peer-limit", &i ) )
484        tr_sessionSetPeerLimit( h, i );
485    if( tr_bencDictFindInt( args_in, "port", &i ) )
486        tr_sessionSetPublicPort( h, i );
487    if( tr_bencDictFindInt( args_in, "port-forwarding-enabled", &i ) )
488        tr_sessionSetPortForwardingEnabled( h, i );
489    if( tr_bencDictFindInt( args_in, "pex-allowed", &i ) )
490        tr_sessionSetPexEnabled( h, i );
491    if( tr_bencDictFindInt( args_in, "speed-limit-down", &i ) )
492        tr_sessionSetSpeedLimit( h, TR_DOWN, i );
493    if( tr_bencDictFindInt( args_in, "speed-limit-down-enabled", &i ) )
494        tr_sessionSetSpeedLimitEnabled( h, TR_DOWN, i );
495    if( tr_bencDictFindInt( args_in, "speed-limit-up", &i ) )
496        tr_sessionSetSpeedLimit( h, TR_UP, i );
497    if( tr_bencDictFindInt( args_in, "speed-limit-up-enabled", &i ) )
498        tr_sessionSetSpeedLimitEnabled( h, TR_UP, i );
499    if( tr_bencDictFindStr( args_in, "encryption", &str ) ) {
500        if( !strcmp( str, "required" ) )
501            tr_sessionSetEncryption( h, TR_ENCRYPTION_REQUIRED );
502        else if( !strcmp( str, "tolerated" ) )
503            tr_sessionSetEncryption( h, TR_PLAINTEXT_PREFERRED );
504        else
505            tr_sessionSetEncryption( h, TR_ENCRYPTION_PREFERRED );
506    }
507
508    return NULL;
509}
510
511static const char*
512sessionGet( tr_handle * h, tr_benc * args_in UNUSED, tr_benc * args_out )
513{
514    const char * str;
515    tr_benc * d = tr_bencDictAddDict( args_out, "session", 9 );
516
517    tr_bencDictAddInt( d, "peer-limit",
518                          tr_sessionGetPeerLimit( h ) );
519    tr_bencDictAddInt( d, "port",
520                          tr_sessionGetPublicPort( h ) );
521    tr_bencDictAddInt( d, "port-forwarding-enabled",
522                          tr_sessionIsPortForwardingEnabled( h ) );
523    tr_bencDictAddInt( d, "pex-allowed",
524                          tr_sessionIsPexEnabled( h ) );
525    tr_bencDictAddInt( d, "speed-limit-up",
526                          tr_sessionGetSpeedLimit( h, TR_UP ) );
527    tr_bencDictAddInt( d, "speed-limit-up-enabled",
528                          tr_sessionIsSpeedLimitEnabled( h, TR_UP ) );
529    tr_bencDictAddInt( d, "speed-limit-down",
530                          tr_sessionGetSpeedLimit( h, TR_DOWN ) );
531    tr_bencDictAddInt( d, "speed-limit-down-enabled",
532                          tr_sessionIsSpeedLimitEnabled( h, TR_DOWN ) );
533    switch( tr_sessionGetEncryption( h ) ) {
534        case TR_PLAINTEXT_PREFERRED: str = "tolerated"; break;
535        case TR_ENCRYPTION_REQUIRED: str = "required"; break;
536        default: str = "preferred"; break;
537    }
538    tr_bencDictAddStr( d, "encryption", str );
539
540
541   
542    return NULL;
543}
544
545/***
546****
547***/
548
549typedef const char* (handler)( tr_handle*, tr_benc*, tr_benc* );
550
551struct request_handler
552{
553    const char * method;
554    handler * func;
555} request_handlers[] = { 
556    { "torrent-start", torrentStart },
557    { "torrent-stop", torrentStop },
558    { "torrent-close", torrentClose },
559    { "torrent-verify", torrentVerify },
560    { "torrent-status", torrentStatus },
561    { "torrent-info", torrentInfo },
562    { "torrent-add", torrentAdd },
563    { "torrent-set", torrentSet },
564    { "torrent-get", torrentGet },
565    { "torrent-set-file", torrentSetFile },
566    { "torrent-get-file", torrentGetFile },
567    { "session-set", sessionSet },
568    { "session-get", sessionGet }
569};
570
571static char*
572request_exec( struct tr_handle * handle,
573              tr_benc          * request,
574              int              * response_len )
575{
576    int64_t i;
577    const char * str;
578    char * out;
579    tr_benc response;
580    tr_benc * args_in = tr_bencDictFind( request, "args" );
581    tr_benc * args_out = NULL;
582    const char * result = NULL;
583
584    /* build the response skeleton */
585    tr_bencInitDict( &response, 3 );
586    if( tr_bencDictFindInt( request, "tag", &i ) )
587        tr_bencDictAddInt( request, "tag", i );
588    args_out = tr_bencDictAddDict( &response, "args", 0 );
589
590    /* parse the request */
591    if( !tr_bencDictFindStr( request, "method", &str ) )
592        result = "no method name";
593    else {
594        const int n = TR_N_ELEMENTS( request_handlers );
595        for( i=0; i<n; ++i )
596            if( !strcmp( str, request_handlers[i].method ) )
597                break;
598        result = i==n
599            ? "method name not recognized"
600            : (*request_handlers[i].func)( handle, args_in, args_out );
601    }
602
603    /* serialize & return the response */
604    if( !result )
605         result = "success";
606    tr_bencDictAddStr( &response, "result", result );
607    out = tr_bencSaveAsJSON( &response, response_len );
608    tr_bencFree( &response );
609    return out;
610}
611
612char*
613tr_rpc_request_exec( struct tr_handle  * handle,
614                     const void        * request_json,
615                     int                 request_len,
616                     int               * response_len )
617{
618    tr_benc top;
619    int have_content = !tr_jsonParse( request_json, (const char*)request_json + request_len, &top, NULL );
620    char * ret = request_exec( handle, have_content ? &top : NULL, response_len );
621    if( have_content )
622        tr_bencFree( &top );
623    return ret;
624}
Note: See TracBrowser for help on using the repository browser.