1
0
Fork 0
mirror of https://github.com/transmission/transmission synced 2025-03-03 10:15:45 +00:00

more work on rpc. bug fixes, regression tests, and spec tweaks.

This commit is contained in:
Charles Kerr 2008-05-13 17:31:09 +00:00
parent 6aaa2fd39e
commit bfd89b685d
4 changed files with 124 additions and 61 deletions

View file

@ -7,18 +7,18 @@
The JSON terminology in RFC 4627 is used. "array" is equivalent The JSON terminology in RFC 4627 is used. "array" is equivalent
to a benc list; "object" is equivalent to a benc dictionary; to a benc list; "object" is equivalent to a benc dictionary;
an object's "strings" are the dictionary's keys, an object's "keys" are the dictionary's string keys,
and an object's "members" are its string/value pairs. and an object's "members" are its key/value pairs.
2. Message Format 2. Message Format
Messages are formatted in a subset of JSON that understands Messages are formatted in a subset of JSON that understands
arrays, maps, strings, and whole numbers with no exponentials -- arrays, maps, strings, and whole numbers with no exponentials --
in short, the subset of JSON easily represented in benc. in short, the subset of JSON easily represented as bencoded data.
floating-point numbers are represented as strings. Floating-point numbers are represented as strings.
booleans are represented as integers where 0 is false and 1 is true. Booleans are represented as integers where 0 is false and 1 is true.
Messages are represented as a JSON objects. There are two types: Messages are represented as JSON objects. There are two types:
requests (described in 2.1) and responses (described in 2.2). requests (described in 2.1) and responses (described in 2.2).
2.1. Requests 2.1. Requests
@ -46,12 +46,12 @@
Method names: "torrent-start", "torrent-stop", Method names: "torrent-start", "torrent-stop",
"torrent-remove", "torrent-verify" "torrent-remove", "torrent-verify"
Request arguments: "ids", a list of unique torrent ids, sha1 hash strings, Request arguments: "ids", a list of torrent id integers, sha1 hash strings,
or both. These are the torrents that the request will or both. These are the torrents that the request will
be applied to. If "ids" is ommitted, the request is be applied to. If "ids" is ommitted, the request is
applied to all torrents. applied to all torrents.
Response arguments: none. Response arguments: none
3.2. Torrent Info Requests 3.2. Torrent Info Requests
@ -71,13 +71,13 @@
{ {
"arguments": { "ids": [ 7, 10 ] } "arguments": { "ids": [ 7, 10 ] }
"method": "torrent-info", "method": "torrent-info",
"tag": 666 "tag": 39693
} }
Example Response: Example Response:
{ {
"tag": 666 "tag": 39693
"result": "success", "result": "success",
"arguments": { "arguments": {
"info": [ "info": [
@ -108,11 +108,11 @@
Request arguments: 3.1's optional "ids" argument. Request arguments: 3.1's optional "ids" argument.
Response arguments: "status", an array of objects based on Response arguments: "status", an array of objects based on
libtransmission's tr_stat struct but which differ the following ways: libtransmission's tr_stat struct but which differ in the following ways:
(1) tr_stat's "tracker" field is omitted (1) tr_stat's "tracker" field is omitted.
(2) a new string, "announce-url", is added (2) a new string, "announce-url", is added.
(3) a new string, "scrape-url", is added (3) a new string, "scrape-url", is added.
3.4. Adding a Torrent 3.4. Adding a Torrent
@ -122,15 +122,15 @@
string | value type & description string | value type & description
-------------------+------------------------------------------------- -------------------+-------------------------------------------------
"paused" | boolean if true, don't start the torrent
"destination" | string path to download the torrent to "destination" | string path to download the torrent to
"filename" | string location of the .torrent file "filename" | string location of the .torrent file
"paused" | boolean if true, don't start the torrent
"peer-limit" | int maximum number of peers "peer-limit" | int maximum number of peers
The "filename" argument is required; all others are optional. The "filename" argument is required; all others are optional.
Response arguments: on success, a "torrent-added" object in the Response arguments: on success, a "torrent-added" object in the
form of one of 3.1's tr_info objects. form of one of 3.2's tr_info objects.
3.5. Other torrent settings 3.5. Other torrent settings
@ -172,16 +172,16 @@
3.6.1. Mutators 3.6.1. Mutators
Method name: "torrent-set-file" Method name: "torrent-set-priorities"
Request arguments: 3.1's "ids", plus one or more of 3.6's arguments Request arguments: 3.1's "ids", plus one or more of 3.6's arguments
Response arguments: none Response arguments: none
3.6.2. Accessors 3.6.2. Accessors
Method name: "torrent-get-file" Method name: "torrent-get-priorities"
Request arguments: none Request arguments: none
Response arguments: A "torrents" list of objects containing all Response arguments: A "torrents" list of objects containing all
of 3.6's arguments plus the torrent's "id" int. of 3.6's arguments plus the torrent's "id" int.
4. Session Status Requests 4. Session Status Requests
@ -191,9 +191,9 @@
---------------------------+------------------------------------------------- ---------------------------+-------------------------------------------------
"encryption" | string "required", "preferred", "tolerated" "encryption" | string "required", "preferred", "tolerated"
"peer-limit" | int maximum global number of peers "peer-limit" | int maximum global number of peers
"pex-allowed" | boolean true means allow pex in public torrents
"port" | int port number "port" | int port number
"port-forwarding-enabled" | boolean true means enabled. "port-forwarding-enabled" | boolean true means enabled.
"pex-allowed" | boolean true means allow pex in public torrents
"speed-limit-down" | int max global download speed (in KiB/s) "speed-limit-down" | int max global download speed (in KiB/s)
"speed-limit-down-enabled" | int max global download speed (in KiB/s) "speed-limit-down-enabled" | int max global download speed (in KiB/s)
"speed-limit-up" | int max global upload speed (in KiB/s) "speed-limit-up" | int max global upload speed (in KiB/s)

View file

@ -275,10 +275,8 @@ static int
testRISONSnippet( const char * rison_str, const char * expected ) testRISONSnippet( const char * rison_str, const char * expected )
{ {
char * serialized = tr_rison2json( rison_str, -1 ); char * serialized = tr_rison2json( rison_str, -1 );
#if 0
fprintf( stderr, " expected: [%s]\n", expected ); fprintf( stderr, " expected: [%s]\n", expected );
fprintf( stderr, " got: [%s]\n", serialized ); fprintf( stderr, " got: [%s]\n", serialized );
#endif
check( !strcmp( serialized, expected ) ); check( !strcmp( serialized, expected ) );
tr_free( serialized ); tr_free( serialized );
return 0; return 0;
@ -296,6 +294,11 @@ testRISON( void )
if(( val = testRISONSnippet( rison, expected ))) if(( val = testRISONSnippet( rison, expected )))
return val; return val;
rison = "(method:torrent-info)";
expected = "{ \"method\": \"torrent-info\" }";
if(( val = testRISONSnippet( rison, expected )))
return val;
return 0; return 0;
} }

View file

@ -204,6 +204,7 @@ tr_rison2json( const char * str, int rison_len )
case '\'': evbuffer_add_printf( out, "\"" ); mode = OTHER; break; case '\'': evbuffer_add_printf( out, "\"" ); mode = OTHER; break;
case ':': evbuffer_add_printf( out, "\": "); mode = VAL_BEGIN; break; case ':': evbuffer_add_printf( out, "\": "); mode = VAL_BEGIN; break;
case '!': mode = ESCAPE_UNQUOTED_STRING; break; case '!': mode = ESCAPE_UNQUOTED_STRING; break;
case ')': if( IN_OBJECT ) { evbuffer_add_printf( out, "\" }"); mode = OTHER; break; }
case ',': if( IN_OBJECT ) { evbuffer_add_printf( out, "\", "); mode = STRING_BEGIN; break; } case ',': if( IN_OBJECT ) { evbuffer_add_printf( out, "\", "); mode = STRING_BEGIN; break; }
/* fallthrough */ /* fallthrough */
default: evbuffer_add_printf( out, "%c", *str ); break; default: evbuffer_add_printf( out, "%c", *str ); break;

View file

@ -69,7 +69,8 @@ getTorrents( tr_handle * handle, tr_benc * args, int * setmeCount )
typedef void( *tor_func )( tr_torrent * tor ); typedef void( *tor_func )( tr_torrent * tor );
static void callTorrentFunc( tr_handle * h, tr_benc * args_in, tor_func func ) static void
callTorrentFunc( tr_handle * h, tr_benc * args_in, tor_func func )
{ {
int i, torrentCount; int i, torrentCount;
tr_torrent ** torrents = getTorrents( h, args_in, &torrentCount ); tr_torrent ** torrents = getTorrents( h, args_in, &torrentCount );
@ -164,7 +165,8 @@ torrentStatus( tr_handle * handle, tr_benc * args_in, tr_benc * args_out )
tr_bencDictAddInt( t, "nextScrapeTime", s->nextScrapeTime ); tr_bencDictAddInt( t, "nextScrapeTime", s->nextScrapeTime );
tr_bencDictAddInt( t, "lastAnnounceTime", s->lastAnnounceTime ); tr_bencDictAddInt( t, "lastAnnounceTime", s->lastAnnounceTime );
tr_bencDictAddInt( t, "nextAnnounceTime", s->nextAnnounceTime ); tr_bencDictAddInt( t, "nextAnnounceTime", s->nextAnnounceTime );
tr_bencDictAddInt( t, "nextManualAnnounceTime", s->nextManualAnnounceTime ); tr_bencDictAddInt( t, "nextManualAnnounceTime",
s->nextManualAnnounceTime );
} }
/* cleanup */ /* cleanup */
@ -172,6 +174,10 @@ torrentStatus( tr_handle * handle, tr_benc * args_in, tr_benc * args_out )
return NULL; return NULL;
} }
/**
***
**/
static void static void
addFiles( const tr_info * info, tr_benc * files ) addFiles( const tr_info * info, tr_benc * files )
{ {
@ -202,24 +208,24 @@ addTrackers( const tr_info * info, tr_benc * trackers )
} }
static void static void
serializeInfo( const tr_torrent * tor, tr_benc * d ) addInfo( const tr_torrent * tor, tr_benc * d )
{ {
const tr_info * inf = tr_torrentInfo( tor ); const tr_info * inf = tr_torrentInfo( tor );
tr_bencInitDict( d, 14 ); tr_bencInitDict( d, 14 );
tr_bencDictAddInt( d, "id", tor->uniqueId );
tr_bencDictAddStr( d, "torrent", inf->torrent );
tr_bencDictAddStr( d, "hashString", inf->hashString );
tr_bencDictAddStr( d, "name", inf->name );
tr_bencDictAddStr( d, "comment", inf->comment ? inf->comment : "" ); tr_bencDictAddStr( d, "comment", inf->comment ? inf->comment : "" );
tr_bencDictAddStr( d, "creator", inf->creator ? inf->creator : "" ); tr_bencDictAddStr( d, "creator", inf->creator ? inf->creator : "" );
tr_bencDictAddInt( d, "isPrivate", inf->isPrivate );
tr_bencDictAddInt( d, "isMultifile", inf->isMultifile );
tr_bencDictAddInt( d, "dateCreated", inf->dateCreated ); tr_bencDictAddInt( d, "dateCreated", inf->dateCreated );
tr_bencDictAddInt( d, "pieceSize", inf->pieceSize ); tr_bencDictAddStr( d, "hashString", inf->hashString );
tr_bencDictAddInt( d, "id", tor->uniqueId );
tr_bencDictAddInt( d, "isMultifile", inf->isMultifile );
tr_bencDictAddInt( d, "isPrivate", inf->isPrivate );
tr_bencDictAddStr( d, "name", inf->name );
tr_bencDictAddInt( d, "pieceCount", inf->pieceCount ); tr_bencDictAddInt( d, "pieceCount", inf->pieceCount );
tr_bencDictAddInt( d, "pieceSize", inf->pieceSize );
tr_bencDictAddStr( d, "torrent", inf->torrent );
tr_bencDictAddInt( d, "totalSize", inf->totalSize ); tr_bencDictAddInt( d, "totalSize", inf->totalSize );
addFiles ( inf, tr_bencDictAddList( d, "files", inf->fileCount ) ); addFiles ( inf, tr_bencDictAddList( d, "files", inf->fileCount ) );
addTrackers( inf, tr_bencDictAddList( d, "files", inf->trackerCount ) ); addTrackers( inf, tr_bencDictAddList( d, "trackers", inf->trackerCount ) );
} }
static const char* static const char*
@ -227,15 +233,19 @@ torrentInfo( tr_handle * handle, tr_benc * args_in, tr_benc * args_out )
{ {
int i, torrentCount; int i, torrentCount;
tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount ); tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
tr_benc * list = tr_bencDictAddList( args_out, "status", torrentCount ); tr_benc * list = tr_bencDictAddList( args_out, "info", torrentCount );
for( i=0; i<torrentCount; ++i ) for( i=0; i<torrentCount; ++i )
serializeInfo( torrents[i], tr_bencListAdd( list ) ); addInfo( torrents[i], tr_bencListAdd( list ) );
tr_free( torrents ); tr_free( torrents );
return NULL; return NULL;
} }
/**
***
**/
static const char* static const char*
torrentGet( tr_handle * handle, tr_benc * args_in, tr_benc * args_out ) torrentGet( tr_handle * handle, tr_benc * args_in, tr_benc * args_out )
{ {
@ -345,7 +355,7 @@ buildFileList( const tr_torrent * tor, tr_benc * dict,
} }
static const char* static const char*
torrentGetFile( tr_handle * handle, tr_benc * args_in, tr_benc * args_out ) torrentGetPriorities( tr_handle * handle, tr_benc * args_in, tr_benc * args_out )
{ {
int i, torrentCount; int i, torrentCount;
tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount ); tr_torrent ** torrents = getTorrents( handle, args_in, &torrentCount );
@ -356,11 +366,11 @@ torrentGetFile( tr_handle * handle, tr_benc * args_in, tr_benc * args_out )
const tr_torrent * tor = torrents[i]; const tr_torrent * tor = torrents[i];
tr_benc * d = tr_bencListAddDict( list, 6 ); tr_benc * d = tr_bencListAddDict( list, 6 );
tr_bencDictAddInt( d, "id", tor->uniqueId ); tr_bencDictAddInt( d, "id", tor->uniqueId );
buildFileList( tor, d, "priority-high", testFileHigh );
buildFileList( tor, d, "priority-low", testFileLow );
buildFileList( tor, d, "priority-normal", testFileNormal );
buildFileList( tor, d, "download", testFileDownload ); buildFileList( tor, d, "download", testFileDownload );
buildFileList( tor, d, "no-download", testFileDND ); buildFileList( tor, d, "no-download", testFileDND );
buildFileList( tor, d, "priority-low", testFileLow );
buildFileList( tor, d, "priority-normal", testFileNormal );
buildFileList( tor, d, "priority-high", testFileHigh );
} }
tr_free( torrents ); tr_free( torrents );
@ -370,10 +380,10 @@ torrentGetFile( tr_handle * handle, tr_benc * args_in, tr_benc * args_out )
static void static void
setFilePriorities( tr_torrent * tor, int priority, tr_benc * list ) setFilePriorities( tr_torrent * tor, int priority, tr_benc * list )
{ {
const int n = tr_bencListSize( list );
int i; int i;
int64_t tmp; int64_t tmp;
int fileCount = 0; int fileCount = 0;
const int n = tr_bencListSize( list );
tr_file_index_t * files = tr_new0( tr_file_index_t, n ); tr_file_index_t * files = tr_new0( tr_file_index_t, n );
for( i=0; i<n; ++i ) for( i=0; i<n; ++i )
@ -389,10 +399,10 @@ setFilePriorities( tr_torrent * tor, int priority, tr_benc * list )
static void static void
setFileDLs( tr_torrent * tor, int do_download, tr_benc * list ) setFileDLs( tr_torrent * tor, int do_download, tr_benc * list )
{ {
const int n = tr_bencListSize( list );
int i; int i;
int64_t tmp; int64_t tmp;
int fileCount = 0; int fileCount = 0;
const int n = tr_bencListSize( list );
tr_file_index_t * files = tr_new0( tr_file_index_t, n ); tr_file_index_t * files = tr_new0( tr_file_index_t, n );
for( i=0; i<n; ++i ) for( i=0; i<n; ++i )
@ -406,7 +416,7 @@ setFileDLs( tr_torrent * tor, int do_download, tr_benc * list )
} }
static const char* static const char*
torrentSetFile( tr_handle * h, tr_benc * args_in, tr_benc * args_out UNUSED ) torrentSetPriorities( tr_handle * h, tr_benc * args_in, tr_benc * args_out UNUSED )
{ {
int i, torrentCount; int i, torrentCount;
tr_torrent ** torrents = getTorrents( h, args_in, &torrentCount ); tr_torrent ** torrents = getTorrents( h, args_in, &torrentCount );
@ -451,17 +461,17 @@ torrentAdd( tr_handle * h, tr_benc * args_in, tr_benc * args_out )
ctor = tr_ctorNew( h ); ctor = tr_ctorNew( h );
tr_ctorSetMetainfoFromFile( ctor, filename ); tr_ctorSetMetainfoFromFile( ctor, filename );
if( tr_bencDictFindStr( args_in, "destination", &str ) )
tr_ctorSetDestination( ctor, TR_FORCE, str );
if( tr_bencDictFindInt( args_in, "paused", &i ) ) if( tr_bencDictFindInt( args_in, "paused", &i ) )
tr_ctorSetPaused( ctor, TR_FORCE, i ); tr_ctorSetPaused( ctor, TR_FORCE, i );
if( tr_bencDictFindInt( args_in, "peer-limit", &i ) ) if( tr_bencDictFindInt( args_in, "peer-limit", &i ) )
tr_ctorSetPeerLimit( ctor, TR_FORCE, i ); tr_ctorSetPeerLimit( ctor, TR_FORCE, i );
if( tr_bencDictFindStr( args_in, "destination", &str ) )
tr_ctorSetDestination( ctor, TR_FORCE, str );
tor = tr_torrentNew( h, ctor, &err ); tor = tr_torrentNew( h, ctor, &err );
tr_ctorFree( ctor ); tr_ctorFree( ctor );
if( tor ) if( tor )
serializeInfo( tor, tr_bencDictAdd( args_out, "torrent-added" ) ); addInfo( tor, tr_bencDictAdd( args_out, "torrent-added" ) );
else if( err == TR_EDUPLICATE ) else if( err == TR_EDUPLICATE )
return "duplicate torrent"; return "duplicate torrent";
else if( err == TR_EINVALID ) else if( err == TR_EINVALID )
@ -483,12 +493,12 @@ sessionSet( tr_handle * h, tr_benc * args_in, tr_benc * args_out UNUSED )
if( tr_bencDictFindInt( args_in, "peer-limit", &i ) ) if( tr_bencDictFindInt( args_in, "peer-limit", &i ) )
tr_sessionSetPeerLimit( h, i ); tr_sessionSetPeerLimit( h, i );
if( tr_bencDictFindInt( args_in, "pex-allowed", &i ) )
tr_sessionSetPexEnabled( h, i );
if( tr_bencDictFindInt( args_in, "port", &i ) ) if( tr_bencDictFindInt( args_in, "port", &i ) )
tr_sessionSetPublicPort( h, i ); tr_sessionSetPublicPort( h, i );
if( tr_bencDictFindInt( args_in, "port-forwarding-enabled", &i ) ) if( tr_bencDictFindInt( args_in, "port-forwarding-enabled", &i ) )
tr_sessionSetPortForwardingEnabled( h, i ); tr_sessionSetPortForwardingEnabled( h, i );
if( tr_bencDictFindInt( args_in, "pex-allowed", &i ) )
tr_sessionSetPexEnabled( h, i );
if( tr_bencDictFindInt( args_in, "speed-limit-down", &i ) ) if( tr_bencDictFindInt( args_in, "speed-limit-down", &i ) )
tr_sessionSetSpeedLimit( h, TR_DOWN, i ); tr_sessionSetSpeedLimit( h, TR_DOWN, i );
if( tr_bencDictFindInt( args_in, "speed-limit-down-enabled", &i ) ) if( tr_bencDictFindInt( args_in, "speed-limit-down-enabled", &i ) )
@ -517,12 +527,12 @@ sessionGet( tr_handle * h, tr_benc * args_in UNUSED, tr_benc * args_out )
tr_bencDictAddInt( d, "peer-limit", tr_bencDictAddInt( d, "peer-limit",
tr_sessionGetPeerLimit( h ) ); tr_sessionGetPeerLimit( h ) );
tr_bencDictAddInt( d, "pex-allowed",
tr_sessionIsPexEnabled( h ) );
tr_bencDictAddInt( d, "port", tr_bencDictAddInt( d, "port",
tr_sessionGetPublicPort( h ) ); tr_sessionGetPublicPort( h ) );
tr_bencDictAddInt( d, "port-forwarding-enabled", tr_bencDictAddInt( d, "port-forwarding-enabled",
tr_sessionIsPortForwardingEnabled( h ) ); tr_sessionIsPortForwardingEnabled( h ) );
tr_bencDictAddInt( d, "pex-allowed",
tr_sessionIsPexEnabled( h ) );
tr_bencDictAddInt( d, "speed-limit-up", tr_bencDictAddInt( d, "speed-limit-up",
tr_sessionGetSpeedLimit( h, TR_UP ) ); tr_sessionGetSpeedLimit( h, TR_UP ) );
tr_bencDictAddInt( d, "speed-limit-up-enabled", tr_bencDictAddInt( d, "speed-limit-up-enabled",
@ -549,11 +559,11 @@ sessionGet( tr_handle * h, tr_benc * args_in UNUSED, tr_benc * args_out )
typedef const char* (handler)( tr_handle*, tr_benc*, tr_benc* ); typedef const char* (handler)( tr_handle*, tr_benc*, tr_benc* );
struct request_handler struct method
{ {
const char * method; const char * name;
handler * func; handler * func;
} request_handlers[] = { } methods[] = {
{ "torrent-start", torrentStart }, { "torrent-start", torrentStart },
{ "torrent-stop", torrentStop }, { "torrent-stop", torrentStop },
{ "torrent-close", torrentClose }, { "torrent-close", torrentClose },
@ -563,8 +573,8 @@ struct request_handler
{ "torrent-add", torrentAdd }, { "torrent-add", torrentAdd },
{ "torrent-set", torrentSet }, { "torrent-set", torrentSet },
{ "torrent-get", torrentGet }, { "torrent-get", torrentGet },
{ "torrent-set-file", torrentSetFile }, { "torrent-set-priorities", torrentSetPriorities },
{ "torrent-get-file", torrentGetFile }, { "torrent-get-priorities", torrentGetPriorities },
{ "session-set", sessionSet }, { "session-set", sessionSet },
{ "session-get", sessionGet } { "session-get", sessionGet }
}; };
@ -592,13 +602,13 @@ request_exec( struct tr_handle * handle,
if( !tr_bencDictFindStr( request, "method", &str ) ) if( !tr_bencDictFindStr( request, "method", &str ) )
result = "no method name"; result = "no method name";
else { else {
const int n = TR_N_ELEMENTS( request_handlers ); const int n = TR_N_ELEMENTS( methods );
for( i=0; i<n; ++i ) for( i=0; i<n; ++i )
if( !strcmp( str, request_handlers[i].method ) ) if( !strcmp( str, methods[i].name ) )
break; break;
result = i==n result = i==n
? "method name not recognized" ? "method name not recognized"
: (*request_handlers[i].func)( handle, args_in, args_out ); : (*methods[i].func)( handle, args_in, args_out );
} }
/* serialize & return the response */ /* serialize & return the response */
@ -639,8 +649,57 @@ tr_rpc_request_exec_rison( struct tr_handle * handle,
int request_len, int request_len,
int * response_len ) int * response_len )
{ {
char * json = tr_rison2json( request_rison, request_len ); char * ret = NULL;
char * ret = tr_rpc_request_exec_json( handle, json, -1, response_len ); tr_benc top;
tr_free( json ); int have_content;
char * request = tr_strndup( request_rison, request_len );;
fprintf( stderr, "passed in: --> %s <--\n", request );
/* possibly convert o-rison to rison */
if( request && ( *request != '(' ) )
{
const int n = strlen( request );
char * tmp = tr_new( char, n + 3 );
tmp[0] = '(';
memcpy( tmp+1, request, n );
tmp[n+1] = ')';
tmp[n+2] = '\0';
tr_free( request );
request = tmp;
}
fprintf( stderr, "after o-rison conversion: --> %s <--\n", request );
/* convert rison to json */
{
char * tmp = tr_rison2json( request, strlen( request ) );
tr_free( request );
request = tmp;
}
fprintf( stderr, "after json conversion: --> %s <--\n", request );
/* parse the json */
have_content = !tr_jsonParse( request, request+strlen(request), &top, NULL );
if( have_content )
{
/* for convenience' sake, our URI rpc notation allows the
* `args' object to be declared implicitly... */
tr_benc tmp, *args;
int64_t i;
const char * str;
tr_bencInitDict( &tmp, 3 );
if( tr_bencDictFindInt( &top, "tag", &i ) )
tr_bencDictAddInt( &tmp, "tag", i );
if( tr_bencDictFindStr( &top, "method", &str ) )
tr_bencDictAddStr( &tmp, "method", str );
args = tr_bencDictAdd( &tmp, "args" );
*args = top;
tr_bencPrint( &tmp);
ret = request_exec( handle, &tmp, response_len );
tr_bencInitInt( args, 0 );
tr_bencFree( &tmp );
tr_bencFree( &top );
}
tr_free( request );
return ret; return ret;
} }