Changeset 7744
- Timestamp:
- Jan 18, 2009, 3:24:26 PM (13 years ago)
- Location:
- trunk
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/daemon/remote.c
r7736 r7744 301 301 else 302 302 { 303 fprintf( stderr, "Couldn't add file: %s\n", optarg);304 addArg = FALSE;303 tr_bencDictAddStr( &top, "method", "torrent-add" ); 304 tr_bencDictAddStr( args, "filename", optarg ); 305 305 } 306 306 } -
trunk/doc/rpc-spec.txt
r7732 r7744 282 282 -------------------+------------------------------------------------- 283 283 "download-dir" | string path to download the torrent to 284 "filename" | string locationof the .torrent file284 "filename" | string filename or URL of the .torrent file 285 285 "metainfo" | string base64-encoded .torrent content 286 286 "paused" | 'boolean' if true, don't start the torrent -
trunk/libtransmission/rpc-server.c
r7706 r7744 177 177 EVBUFFER_DATA( json ), 178 178 EVBUFFER_LENGTH( json ), 179 NULL );179 NULL, NULL ); 180 180 181 181 tr_releaseBuffer( json ); … … 375 375 } 376 376 377 struct rpc_response_data 378 { 379 struct evhttp_request * req; 380 struct tr_rpc_server * server; 381 }; 382 383 static void 384 rpc_response_func( tr_session * session UNUSED, 385 const char * response, 386 size_t response_len, 387 void * user_data ) 388 { 389 struct rpc_response_data * data = user_data; 390 struct evbuffer * buf = tr_getBuffer( ); 391 392 add_response( data->req, data->server, buf, response, response_len ); 393 evhttp_add_header( data->req->output_headers, 394 "Content-Type", "application/json; charset=UTF-8" ); 395 evhttp_send_reply( data->req, HTTP_OK, "OK", buf ); 396 397 tr_releaseBuffer( buf ); 398 tr_free( data ); 399 } 400 401 377 402 static void 378 403 handle_rpc( struct evhttp_request * req, 379 404 struct tr_rpc_server * server ) 380 405 { 381 struct evbuffer * response = tr_getBuffer( ); 382 406 struct rpc_response_data * data = tr_new0( struct rpc_response_data, 1 ); 407 408 data->req = req; 409 data->server = server; 410 383 411 if( req->type == EVHTTP_REQ_GET ) 384 412 { 385 413 const char * q; 386 414 if( ( q = strchr( req->uri, '?' ) ) ) 387 tr_rpc_request_exec_uri( server->session, q + 1, strlen( q + 1 ), response);415 tr_rpc_request_exec_uri( server->session, q+1, -1, rpc_response_func, data ); 388 416 } 389 417 else if( req->type == EVHTTP_REQ_POST ) … … 392 420 EVBUFFER_DATA( req->input_buffer ), 393 421 EVBUFFER_LENGTH( req->input_buffer ), 394 response ); 395 } 396 397 { 398 struct evbuffer * buf = tr_getBuffer( ); 399 add_response( req, server, buf, 400 EVBUFFER_DATA( response ), 401 EVBUFFER_LENGTH( response ) ); 402 evhttp_add_header( req->output_headers, "Content-Type", 403 "application/json; charset=UTF-8" ); 404 evhttp_send_reply( req, HTTP_OK, "OK", buf ); 405 tr_releaseBuffer( buf ); 406 } 407 408 /* cleanup */ 409 tr_releaseBuffer( response ); 422 rpc_response_func, data ); 423 } 424 410 425 } 411 426 -
trunk/libtransmission/rpcimpl.c
r7732 r7744 16 16 #include <string.h> /* strcmp */ 17 17 18 #include <event.h> /* evbuffer */ 19 18 20 #include "transmission.h" 19 21 #include "bencode.h" … … 23 25 #include "torrent.h" 24 26 #include "utils.h" 27 #include "web.h" 25 28 26 29 #define TR_N_ELEMENTS( ary ) ( sizeof( ary ) / sizeof( *ary ) ) 30 31 #define dbgmsg( ... ) \ 32 do { \ 33 if( tr_deepLoggingIsActive( ) ) \ 34 tr_deepLog( __FILE__, __LINE__, "RPC", __VA_ARGS__ ); \ 35 } while( 0 ) 36 27 37 28 38 /*** … … 42 52 43 53 return status; 54 } 55 56 /*** 57 **** 58 ***/ 59 60 /* For functions that can't be immediately executed, like torrentAdd, 61 * this is the callback data used to pass a response to the caller 62 * when the task is complete */ 63 struct tr_rpc_idle_data 64 { 65 tr_session * session; 66 tr_benc * response; 67 tr_benc * args_out; 68 tr_rpc_response_func * callback; 69 void * callback_user_data; 70 }; 71 72 static void 73 function_done( struct tr_rpc_idle_data * data, const char * result ) 74 { 75 struct evbuffer * buf = tr_getBuffer( ); 76 77 if( result == NULL ) 78 result = "success"; 79 tr_bencDictAddStr( data->response, "result", result ); 80 81 tr_bencSaveAsJSON( data->response, buf ); 82 data->callback( data->session, (const char*)EVBUFFER_DATA(buf), 83 EVBUFFER_LENGTH(buf), data->callback_user_data ); 84 85 tr_releaseBuffer( buf ); 86 tr_bencFree( data->response ); 87 tr_free( data->response ); 88 tr_free( data ); 44 89 } 45 90 … … 100 145 101 146 static const char* 102 torrentStart( tr_session * session, 103 tr_benc * args_in, 104 tr_benc * args_out UNUSED ) 147 torrentStart( tr_session * session, 148 tr_benc * args_in, 149 tr_benc * args_out UNUSED, 150 struct tr_rpc_idle_data * idle_data ) 105 151 { 106 152 int i, torrentCount; 107 153 tr_torrent ** torrents = getTorrents( session, args_in, &torrentCount ); 154 155 assert( idle_data == NULL ); 108 156 109 157 for( i = 0; i < torrentCount; ++i ) … … 118 166 119 167 static const char* 120 torrentStop( tr_session * session, 121 tr_benc * args_in, 122 tr_benc * args_out UNUSED ) 168 torrentStop( tr_session * session, 169 tr_benc * args_in, 170 tr_benc * args_out UNUSED, 171 struct tr_rpc_idle_data * idle_data ) 123 172 { 124 173 int i, torrentCount; 125 174 tr_torrent ** torrents = getTorrents( session, args_in, &torrentCount ); 175 176 assert( idle_data == NULL ); 126 177 127 178 for( i = 0; i < torrentCount; ++i ) … … 136 187 137 188 static const char* 138 torrentRemove( tr_session * session, 139 tr_benc * args_in, 140 tr_benc * args_out UNUSED ) 189 torrentRemove( tr_session * session, 190 tr_benc * args_in, 191 tr_benc * args_out UNUSED, 192 struct tr_rpc_idle_data * idle_data ) 141 193 { 142 194 int i; 143 195 int torrentCount; 144 196 tr_torrent ** torrents = getTorrents( session, args_in, &torrentCount ); 197 198 assert( idle_data == NULL ); 145 199 146 200 for( i=0; i<torrentCount; ++i ) … … 160 214 161 215 static const char* 162 torrentVerify( tr_session * session, 163 tr_benc * args_in, 164 tr_benc * args_out UNUSED ) 216 torrentVerify( tr_session * session, 217 tr_benc * args_in, 218 tr_benc * args_out UNUSED, 219 struct tr_rpc_idle_data * idle_data ) 165 220 { 166 221 int i, torrentCount; 167 222 tr_torrent ** torrents = getTorrents( session, args_in, &torrentCount ); 223 224 assert( idle_data == NULL ); 168 225 169 226 for( i = 0; i < torrentCount; ++i ) … … 436 493 437 494 static const char* 438 torrentGet( tr_session * session, 439 tr_benc * args_in, 440 tr_benc * args_out ) 495 torrentGet( tr_session * session, 496 tr_benc * args_in, 497 tr_benc * args_out, 498 struct tr_rpc_idle_data * idle_data ) 441 499 { 442 500 int i, torrentCount; 443 501 tr_torrent ** torrents = getTorrents( session, args_in, &torrentCount ); 444 tr_benc * list = tr_bencDictAddList( args_out, "torrents", 445 torrentCount ); 502 tr_benc * list = tr_bencDictAddList( args_out, "torrents", torrentCount ); 446 503 tr_benc * fields; 447 504 char * msg = NULL; 505 506 assert( idle_data == NULL ); 448 507 449 508 if( !tr_bencDictFindList( args_in, "fields", &fields ) ) … … 523 582 524 583 static const char* 525 torrentSet( tr_session * session, 526 tr_benc * args_in, 527 tr_benc * args_out UNUSED ) 584 torrentSet( tr_session * session, 585 tr_benc * args_in, 586 tr_benc * args_out UNUSED, 587 struct tr_rpc_idle_data * idle_data ) 528 588 { 529 589 int i, torrentCount; 530 590 tr_torrent ** torrents = getTorrents( session, args_in, &torrentCount ); 591 592 assert( idle_data == NULL ); 531 593 532 594 for( i = 0; i < torrentCount; ++i ) … … 571 633 ***/ 572 634 635 static void 636 addTorrentImpl( struct tr_rpc_idle_data * data, tr_ctor * ctor ) 637 { 638 int err = 0; 639 const char * result = NULL; 640 tr_torrent * tor = tr_torrentNew( data->session, ctor, &err ); 641 642 tr_ctorFree( ctor ); 643 644 if( tor ) 645 { 646 tr_benc fields; 647 tr_bencInitList( &fields, 3 ); 648 tr_bencListAddStr( &fields, "id" ); 649 tr_bencListAddStr( &fields, "name" ); 650 tr_bencListAddStr( &fields, "hashString" ); 651 addInfo( tor, tr_bencDictAdd( data->args_out, "torrent-added" ), &fields ); 652 notify( data->session, TR_RPC_TORRENT_ADDED, tor ); 653 tr_bencFree( &fields ); 654 } 655 else if( err == TR_EDUPLICATE ) 656 { 657 result = "duplicate torrent"; 658 } 659 else if( err == TR_EINVALID ) 660 { 661 result = "invalid or corrupt torrent file"; 662 } 663 664 function_done( data, result ); 665 } 666 667 668 struct add_torrent_idle_data 669 { 670 struct tr_rpc_idle_data * data; 671 tr_ctor * ctor; 672 }; 673 674 static void 675 gotMetadataFromURL( tr_session * session UNUSED, 676 long response_code, 677 const void * response, 678 size_t response_byte_count, 679 void * user_data ) 680 { 681 struct add_torrent_idle_data * data = user_data; 682 683 dbgmsg( "torrentAdd: HTTP response code was %ld (%s); response length was %zu bytes", 684 response_code, tr_webGetResponseStr( response_code ), response_byte_count ); 685 686 if( response_code == 200 ) 687 { 688 tr_ctorSetMetainfo( data->ctor, response, response_byte_count ); 689 addTorrentImpl( data->data, data->ctor ); 690 } 691 else 692 { 693 char result[1024]; 694 tr_snprintf( result, sizeof( result ), "http error %ld: %s", 695 response_code, tr_webGetResponseStr( response_code ) ); 696 function_done( data->data, result ); 697 } 698 699 tr_free( data ); 700 } 701 702 static tr_bool 703 isCurlURL( const char * filename ) 704 { 705 if( filename == NULL ) 706 return FALSE; 707 708 return ( strstr( filename, "ftp://" ) != NULL ) 709 || ( strstr( filename, "http://" ) != NULL ) 710 || ( strstr( filename, "https://" ) != NULL ); 711 } 712 573 713 static const char* 574 torrentAdd( tr_session * session, 575 tr_benc * args_in, 576 tr_benc * args_out ) 714 torrentAdd( tr_session * session, 715 tr_benc * args_in, 716 tr_benc * args_out UNUSED, 717 struct tr_rpc_idle_data * idle_data ) 577 718 { 578 719 const char * filename = NULL; 579 720 const char * metainfo_base64 = NULL; 721 722 assert( idle_data != NULL ); 580 723 581 724 tr_bencDictFindStr( args_in, "filename", &filename ); … … 586 729 { 587 730 int64_t i; 588 int err = 0;589 731 const char * str; 590 tr_ctor * ctor; 591 tr_torrent * tor; 592 593 ctor = tr_ctorNew( session ); 594 595 /* set the metainfo */ 596 if( filename ) 597 tr_ctorSetMetainfoFromFile( ctor, filename ); 598 else 599 { 600 int len; 601 char * metainfo = tr_base64_decode( metainfo_base64, -1, &len ); 602 tr_ctorSetMetainfo( ctor, (uint8_t*)metainfo, len ); 603 tr_free( metainfo ); 604 } 732 tr_ctor * ctor = tr_ctorNew( session ); 605 733 606 734 /* set the optional arguments */ … … 612 740 tr_ctorSetPeerLimit( ctor, TR_FORCE, i ); 613 741 614 tor = tr_torrentNew( session, ctor, &err ); 615 tr_ctorFree( ctor ); 616 617 if( tor ) 742 dbgmsg( "torrentAdd: filename is \"%s\"", filename ); 743 744 if( isCurlURL( filename ) ) 618 745 { 619 tr_benc fields; 620 tr_bencInitList( &fields, 3 ); 621 tr_bencListAddStr( &fields, "id" ); 622 tr_bencListAddStr( &fields, "name" ); 623 tr_bencListAddStr( &fields, "hashString" ); 624 addInfo( tor, tr_bencDictAdd( args_out, 625 "torrent-added" ), &fields ); 626 notify( session, TR_RPC_TORRENT_ADDED, tor ); 627 tr_bencFree( &fields ); 746 struct add_torrent_idle_data * d = tr_new0( struct add_torrent_idle_data, 1 ); 747 d->data = idle_data; 748 d->ctor = ctor; 749 tr_webRun( session, filename, NULL, gotMetadataFromURL, d ); 628 750 } 629 else if( err == TR_EDUPLICATE )751 else 630 752 { 631 return "duplicate torrent"; 753 if( filename != NULL ) 754 tr_ctorSetMetainfoFromFile( ctor, filename ); 755 else { 756 int len; 757 char * metainfo = tr_base64_decode( metainfo_base64, -1, &len ); 758 tr_ctorSetMetainfo( ctor, (uint8_t*)metainfo, len ); 759 tr_free( metainfo ); 760 } 761 addTorrentImpl( idle_data, ctor ); 632 762 } 633 else if( err == TR_EINVALID ) 634 { 635 return "invalid or corrupt torrent file"; 636 } 763 637 764 } 638 765 … … 645 772 646 773 static const char* 647 sessionSet( tr_session * session, 648 tr_benc * args_in, 649 tr_benc * args_out UNUSED ) 774 sessionSet( tr_session * session, 775 tr_benc * args_in, 776 tr_benc * args_out UNUSED, 777 struct tr_rpc_idle_data * idle_data ) 650 778 { 651 779 int64_t i; 652 780 const char * str; 781 782 assert( idle_data == NULL ); 653 783 654 784 if( tr_bencDictFindStr( args_in, "download-dir", &str ) ) … … 686 816 687 817 static const char* 688 sessionStats( tr_session * session, 689 tr_benc * args_in UNUSED, 690 tr_benc * args_out ) 818 sessionStats( tr_session * session, 819 tr_benc * args_in UNUSED, 820 tr_benc * args_out, 821 struct tr_rpc_idle_data * idle_data ) 691 822 { 692 823 int running = 0; 693 824 int total = 0; 694 825 tr_torrent * tor = NULL; 826 827 assert( idle_data == NULL ); 695 828 696 829 while(( tor = tr_torrentNext( session, tor ))) { … … 709 842 710 843 static const char* 711 sessionGet( tr_session * session, 712 tr_benc * args_in UNUSED, 713 tr_benc * args_out ) 844 sessionGet( tr_session * session, 845 tr_benc * args_in UNUSED, 846 tr_benc * args_out, 847 struct tr_rpc_idle_data * idle_data ) 714 848 { 715 849 const char * str; 716 850 tr_benc * d = args_out; 851 852 assert( idle_data == NULL ); 717 853 718 854 tr_bencDictAddStr( d, "download-dir", tr_sessionGetDownloadDir( session ) ); … … 742 878 ***/ 743 879 744 typedef const char* ( handler )( tr_session*, tr_benc*, tr_benc* );880 typedef const char* ( handler )( tr_session*, tr_benc*, tr_benc*, struct tr_rpc_idle_data * ); 745 881 746 882 static struct method 747 883 { 748 884 const char * name; 749 handler * func; 750 } methods[] = { 751 { "session-get", sessionGet }, 752 { "session-set", sessionSet }, 753 { "session-stats", sessionStats }, 754 { "torrent-add", torrentAdd }, 755 { "torrent-get", torrentGet }, 756 { "torrent-remove", torrentRemove }, 757 { "torrent-set", torrentSet }, 758 { "torrent-start", torrentStart }, 759 { "torrent-stop", torrentStop }, 760 { "torrent-verify", torrentVerify } 885 tr_bool immediate; 886 handler * func; 887 } 888 methods[] = 889 { 890 { "session-get", TRUE, sessionGet }, 891 { "session-set", TRUE, sessionSet }, 892 { "session-stats", TRUE, sessionStats }, 893 { "torrent-add", FALSE, torrentAdd }, 894 { "torrent-get", TRUE, torrentGet }, 895 { "torrent-remove", TRUE, torrentRemove }, 896 { "torrent-set", TRUE, torrentSet }, 897 { "torrent-start", TRUE, torrentStart }, 898 { "torrent-stop", TRUE, torrentStop }, 899 { "torrent-verify", TRUE, torrentVerify } 761 900 }; 762 901 763 902 static void 764 request_exec( tr_session * session, 765 tr_benc * request, 766 struct evbuffer * response_buf ) 903 request_exec( tr_session * session, 904 tr_benc * request, 905 tr_rpc_response_func callback, 906 void * callback_user_data ) 767 907 { 768 908 int64_t i; 769 909 const char * str; 770 tr_benc response;771 910 tr_benc * args_in = tr_bencDictFind( request, "arguments" ); 772 tr_benc * args_out = NULL;773 911 const char * result = NULL; 774 775 /* build the response skeleton */776 tr_bencInitDict( &response, 3 );777 args_out = tr_bencDictAddDict( &response, "arguments", 0 );778 912 779 913 /* parse the request */ 780 914 if( !tr_bencDictFindStr( request, "method", &str ) ) 781 915 result = "no method name"; 782 else 783 { 916 else { 784 917 const int n = TR_N_ELEMENTS( methods ); 785 918 for( i = 0; i < n; ++i ) 786 919 if( !strcmp( str, methods[i].name ) ) 787 920 break; 788 result = i == n 789 ? "method name not recognized" 790 : ( *methods[i].func )( session, args_in, args_out ); 791 } 792 793 /* serialize & return the response */ 794 if( !result ) 795 result = "success"; 796 tr_bencDictAddStr( &response, "result", result ); 797 if( tr_bencDictFindInt( request, "tag", &i ) ) 798 tr_bencDictAddInt( &response, "tag", i ); 799 if( response_buf != NULL ) 800 tr_bencSaveAsJSON( &response, response_buf ); 801 tr_bencFree( &response ); 921 if( i ==n ) 922 result = "method name not recognized"; 923 } 924 925 /* if we couldn't figure out which method to use, return an error */ 926 if( result != NULL ) 927 { 928 tr_benc response; 929 struct evbuffer * buf = tr_getBuffer( ); 930 931 tr_bencInitDict( &response, 3 ); 932 tr_bencDictAddDict( &response, "arguments", 0 ); 933 tr_bencDictAddStr( &response, "result", result ); 934 if( tr_bencDictFindInt( request, "tag", &i ) ) 935 tr_bencDictAddInt( &response, "tag", i ); 936 tr_bencSaveAsJSON( &response, buf ); 937 callback( session, (const char*)EVBUFFER_DATA(buf), 938 EVBUFFER_LENGTH( buf ), callback_user_data ); 939 940 tr_releaseBuffer( buf ); 941 tr_bencFree( &response ); 942 } 943 944 if( methods[i].immediate ) 945 { 946 tr_benc response; 947 tr_benc * args_out; 948 struct evbuffer * buf = tr_getBuffer( ); 949 950 tr_bencInitDict( &response, 3 ); 951 args_out = tr_bencDictAddDict( &response, "arguments", 0 ); 952 result = (*methods[i].func)( session, args_in, args_out, NULL ); 953 if( result == NULL ) 954 result = "success"; 955 tr_bencDictAddStr( &response, "result", result ); 956 if( tr_bencDictFindInt( request, "tag", &i ) ) 957 tr_bencDictAddInt( &response, "tag", i ); 958 tr_bencSaveAsJSON( &response, buf ); 959 callback( session, (const char*)EVBUFFER_DATA(buf), 960 EVBUFFER_LENGTH(buf), callback_user_data ); 961 962 tr_releaseBuffer( buf ); 963 tr_bencFree( &response ); 964 } 965 else 966 { 967 struct tr_rpc_idle_data * data = tr_new0( struct tr_rpc_idle_data, 1 ); 968 data->session = session; 969 data->response = tr_new0( tr_benc, 1 ); 970 if( tr_bencDictFindInt( request, "tag", &i ) ) 971 tr_bencDictAddInt( data->response, "tag", i ); 972 tr_bencInitDict( data->response, 3 ); 973 data->args_out = tr_bencDictAddDict( data->response, "arguments", 0 ); 974 data->callback = callback; 975 data->callback_user_data = callback_user_data; 976 (*methods[i].func)( session, args_in, data->args_out, data ); 977 } 802 978 } 803 979 804 980 void 805 tr_rpc_request_exec_json( tr_session * session, 806 const void * request_json, 807 int request_len, 808 struct evbuffer * response ) 981 tr_rpc_request_exec_json( tr_session * session, 982 const void * request_json, 983 ssize_t request_len, 984 tr_rpc_response_func callback, 985 void * callback_user_data ) 809 986 { 810 987 tr_benc top; … … 815 992 816 993 have_content = !tr_jsonParse( request_json, request_len, &top, NULL ); 817 request_exec( session, have_content ? &top : NULL, response);994 request_exec( session, have_content ? &top : NULL, callback, callback_user_data ); 818 995 819 996 if( have_content ) … … 854 1031 */ 855 1032 void 856 tr_rpc_parse_list_str( tr_benc *setme,857 const char * str_in,858 s ize_t len )1033 tr_rpc_parse_list_str( tr_benc * setme, 1034 const char * str_in, 1035 ssize_t len ) 859 1036 860 1037 { … … 901 1078 902 1079 void 903 tr_rpc_request_exec_uri( tr_session * session, 904 const void * request_uri, 905 int request_len, 906 struct evbuffer * response ) 1080 tr_rpc_request_exec_uri( tr_session * session, 1081 const void * request_uri, 1082 ssize_t request_len, 1083 tr_rpc_response_func callback, 1084 void * callback_user_data ) 907 1085 { 908 1086 tr_benc top, * args; … … 934 1112 } 935 1113 936 request_exec( session, &top, response);1114 request_exec( session, &top, callback, callback_user_data ); 937 1115 938 1116 /* cleanup */ -
trunk/libtransmission/rpcimpl.h
r7658 r7744 14 14 #define TR_RPC_H 15 15 16 #include <unistd.h> /* ssize_t */ 17 16 18 /*** 17 19 **** RPC processing 18 20 ***/ 19 21 20 struct evbuffer;21 22 struct tr_benc; 22 23 24 typedef void( tr_rpc_response_func )( tr_session * session, 25 const char * response, 26 size_t response_len, 27 void * user_data ); 23 28 /* http://www.json.org/ */ 24 void tr_rpc_request_exec_json( tr_session * session, 25 const void * request_json, 26 int request_len, 27 struct evbuffer * setme_response ); 29 void tr_rpc_request_exec_json( tr_session * session, 30 const void * request_json, 31 ssize_t request_len, 32 tr_rpc_response_func callback, 33 void * callback_user_data ); 28 34 29 35 /* see the RPC spec's "Request URI Notation" section */ 30 void tr_rpc_request_exec_uri( tr_session * session, 31 const void * request_uri, 32 int request_len, 33 struct evbuffer * setme_response ); 36 void tr_rpc_request_exec_uri( tr_session * session, 37 const void * request_uri, 38 ssize_t request_len, 39 tr_rpc_response_func callback, 40 void * callback_user_data ); 34 41 35 42 void tr_rpc_parse_list_str( struct tr_benc * setme, 36 43 const char * list_str, 37 s ize_tlist_str_len );44 ssize_t list_str_len ); 38 45 39 46
Note: See TracChangeset
for help on using the changeset viewer.