Changeset 6342


Ignore:
Timestamp:
Jul 16, 2008, 5:47:20 PM (13 years ago)
Author:
charles
Message:

(rpc) better handling of multiple concurrent RPC connections

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/rpc-server.c

    r6337 r6342  
    2525#include "transmission.h"
    2626#include "bencode.h"
     27#include "list.h"
    2728#include "platform.h"
    2829#include "rpc.h"
     
    3334#define MY_REALM "Transmission RPC Server"
    3435
    35 #define BUSY_INTERVAL_MSEC 30
    36 #define IDLE_INTERVAL_MSEC 66
    37 #define UNUSED_INTERVAL_MSEC 100
     36#define ACTIVE_INTERVAL_MSEC 40
     37#define INACTIVE_INTERVAL_MSEC 500
    3838
    3939struct tr_rpc_server
     
    4343    struct shttpd_ctx * ctx;
    4444    tr_handle * session;
    45     struct evbuffer * in;
    46     struct evbuffer * out;
    4745    struct event timer;
    4846    int isPasswordEnabled;
     
    5048    char * password;
    5149    char * acl;
     50    tr_list * connections;
    5251};
    5352
     
    5857           const char * s2, size_t l2 )
    5958{
    60         if (!l2) return s1;
    61         while (l1 >= l2) {
    62                 l1--;
    63                 if (!memcmp(s1,s2,l2))
    64                         return s1;
    65                 s1++;
    66         }
    67         return NULL;
    68 }
     59    if (!l2) return s1;
     60    while (l1 >= l2) {
     61        l1--;
     62        if (!memcmp(s1,s2,l2))
     63            return s1;
     64        s1++;
     65    }
     66    return NULL;
     67}
     68
     69/**
     70***
     71**/
     72
     73struct ConnBuf
     74{
     75    char * key;
     76    time_t lastActivity;
     77    struct evbuffer * in;
     78    struct evbuffer * out;
     79};
     80
     81static char*
     82buildKey( struct shttpd_arg * arg )
     83{
     84    return tr_strdup_printf( "%s %s",
     85                             shttpd_get_env( arg, "REMOTE_ADDR" ),
     86                             shttpd_get_env( arg, "REQUEST_URI" ) );
     87}
     88
     89static struct ConnBuf*
     90getBuffer( tr_rpc_server * server, struct shttpd_arg * arg )
     91{
     92    tr_list * l;
     93    char * key = buildKey( arg );
     94    struct ConnBuf * found = NULL;
     95
     96    for( l=server->connections; l && !found; l=l->next )
     97    {
     98        struct ConnBuf * buf = l->data;
     99        if( !strcmp( key, buf->key ) )
     100            found = buf;
     101    }
     102
     103    if( found == NULL )
     104    {
     105        found = tr_new0( struct ConnBuf, 1 );
     106        found->lastActivity = time( NULL );
     107        found->key = tr_strdup( key );
     108        found->in = evbuffer_new( );
     109        found->out = evbuffer_new( );
     110        tr_list_append( &server->connections, found );
     111    }
     112
     113    tr_free( key );
     114    return found;
     115}
     116
     117static void
     118pruneBuf( tr_rpc_server * server, struct ConnBuf * buf )
     119{
     120    tr_list_remove_data( &server->connections, buf );
     121
     122    evbuffer_free( buf->in );
     123    evbuffer_free( buf->out );
     124    tr_free( buf->key );
     125    tr_free( buf );
     126}
     127
     128/**
     129***
     130**/
    69131
    70132static void
     
    73135    struct tr_rpc_server * s = arg->user_data;
    74136    s->lastRequestTime = time( NULL );
     137    struct ConnBuf * cbuf = getBuffer( s, arg );
    75138
    76139    /* if we haven't parsed the POST, do that now */
    77     if( !EVBUFFER_LENGTH( s->out ) )
     140    if( !EVBUFFER_LENGTH( cbuf->out ) )
    78141    {
    79142        /* if we haven't finished reading the POST, read more now */
    80         evbuffer_add( s->in, arg->in.buf, arg->in.len );
     143        evbuffer_add( cbuf->in, arg->in.buf, arg->in.len );
    81144        arg->in.num_bytes = arg->in.len;
    82145        if( arg->flags & SHTTPD_MORE_POST_DATA )
     
    86149        const char * content_type = shttpd_get_header( arg, "Content-Type" );
    87150        const char * delim;
    88         const char * in = (const char *) EVBUFFER_DATA( s->in );
    89         size_t inlen = EVBUFFER_LENGTH( s->in );
     151        const char * in = (const char *) EVBUFFER_DATA( cbuf->in );
     152        size_t inlen = EVBUFFER_LENGTH( cbuf->in );
    90153        char * boundary = tr_strdup_printf( "--%s", strstr( content_type, "boundary=" ) + strlen( "boundary=" ) );
    91154        const size_t boundary_len = strlen( boundary );
     
    143206        while( delim );
    144207
    145         evbuffer_drain( s->in, EVBUFFER_LENGTH( s->in ) );
     208        evbuffer_drain( cbuf->in, EVBUFFER_LENGTH( cbuf->in ) );
    146209        tr_free( boundary );
    147210
     
    151214            const char * response = "<result>success</result>";
    152215            const int len = strlen( response );
    153             evbuffer_add_printf( s->out, "HTTP/1.1 200 OK\r\n"
    154                                          "Content-Type: text/xml\r\n"
    155                                          "Content-Length: %d\r\n"
    156                                          "\r\n"
    157                                          "%s\r\n", len, response );
    158         }
    159     }
    160 
    161     if( EVBUFFER_LENGTH( s->out ) )
    162     {
    163         const int n = MIN( ( int )EVBUFFER_LENGTH( s->out ), arg->out.len );
    164         memcpy( arg->out.buf, EVBUFFER_DATA( s->out ), n );
    165         evbuffer_drain( s->out, n );
     216            evbuffer_add_printf( cbuf->out, "HTTP/1.1 200 OK\r\n"
     217                                            "Content-Type: text/xml\r\n"
     218                                            "Content-Length: %d\r\n"
     219                                            "\r\n"
     220                                           "%s\r\n", len, response );
     221        }
     222    }
     223
     224    if( EVBUFFER_LENGTH( cbuf->out ) )
     225    {
     226        const int n = MIN( ( int )EVBUFFER_LENGTH( cbuf->out ), arg->out.len );
     227        memcpy( arg->out.buf, EVBUFFER_DATA( cbuf->out ), n );
     228        evbuffer_drain( cbuf->out, n );
    166229        arg->out.num_bytes = n;
    167230    }
    168231
    169     if( !EVBUFFER_LENGTH( s->out ) )
     232    if( !EVBUFFER_LENGTH( cbuf->out ) )
     233    {
    170234        arg->flags |= SHTTPD_END_OF_OUTPUT;
     235        pruneBuf( s, cbuf );
     236    }
    171237}
    172238
     
    176242    struct tr_rpc_server * s = arg->user_data;
    177243    s->lastRequestTime = time( NULL );
    178 
    179     if( !EVBUFFER_LENGTH( s->out ) )
     244    struct ConnBuf * cbuf = getBuffer( s, arg );
     245
     246    if( !EVBUFFER_LENGTH( cbuf->out ) )
    180247    {
    181248        int len = 0;
     
    191258        else if( !strcmp( request_method, "POST" ) )
    192259        {
    193             evbuffer_add( s->in, arg->in.buf, arg->in.len );
     260            evbuffer_add( cbuf->in, arg->in.buf, arg->in.len );
    194261            arg->in.num_bytes = arg->in.len;
    195262            if( arg->flags & SHTTPD_MORE_POST_DATA )
    196263                return;
    197264            response = tr_rpc_request_exec_json( s->session,
    198                                                  EVBUFFER_DATA( s->in ),
    199                                                  EVBUFFER_LENGTH( s->in ),
     265                                                 EVBUFFER_DATA( cbuf->in ),
     266                                                 EVBUFFER_LENGTH( cbuf->in ),
    200267                                                 &len );
    201             evbuffer_drain( s->in, EVBUFFER_LENGTH( s->in ) );
    202         }
    203 
    204         evbuffer_add_printf( s->out, "HTTP/1.1 200 OK\r\n"
    205                                      "Content-Type: application/json\r\n"
    206                                      "Content-Length: %d\r\n"
    207                                      "\r\n"
    208                                      "%*.*s", len, len, len, response );
     268            evbuffer_drain( cbuf->in, EVBUFFER_LENGTH( cbuf->in ) );
     269        }
     270
     271        evbuffer_add_printf( cbuf->out, "HTTP/1.1 200 OK\r\n"
     272                                        "Content-Type: application/json\r\n"
     273                                        "Content-Length: %d\r\n"
     274                                        "\r\n"
     275                                        "%*.*s", len, len, len, response );
    209276        tr_free( response );
    210277    }
    211278
    212     if( EVBUFFER_LENGTH( s->out ) )
    213     {
    214         const int n = MIN( ( int )EVBUFFER_LENGTH( s->out ), arg->out.len );
    215         memcpy( arg->out.buf, EVBUFFER_DATA( s->out ), n );
    216         evbuffer_drain( s->out, n );
     279    if( EVBUFFER_LENGTH( cbuf->out ) )
     280    {
     281        const int n = MIN( ( int )EVBUFFER_LENGTH( cbuf->out ), arg->out.len );
     282        memcpy( arg->out.buf, EVBUFFER_DATA( cbuf->out ), n );
     283        evbuffer_drain( cbuf->out, n );
    217284        arg->out.num_bytes = n;
    218285    }
    219286
    220     if( !EVBUFFER_LENGTH( s->out ) )
     287    if( !EVBUFFER_LENGTH( cbuf->out ) )
     288    {
    221289        arg->flags |= SHTTPD_END_OF_OUTPUT;
     290        pruneBuf( s, cbuf );
     291    }
    222292}
    223293
     
    236306
    237307    /* set a timer for the next pulse */
    238     if( EVBUFFER_LENGTH( server->in ) || EVBUFFER_LENGTH( server->out ) )
    239         interval = BUSY_INTERVAL_MSEC;
    240     else if( now - server->lastRequestTime < 300 )
    241         interval = IDLE_INTERVAL_MSEC;
     308    if( now - server->lastRequestTime < 300 )
     309        interval = ACTIVE_INTERVAL_MSEC;
    242310    else
    243         interval = UNUSED_INTERVAL_MSEC;
     311        interval = INACTIVE_INTERVAL_MSEC;
    244312    tv = tr_timevalMsec( interval );
    245313    evtimer_add( &server->timer, &tv );
     
    264332        char passwd[MAX_PATH_LENGTH];
    265333        const char * clutchDir = tr_getClutchDir( server->session );
    266         struct timeval tv = tr_timevalMsec( UNUSED_INTERVAL_MSEC );
     334        struct timeval tv = tr_timevalMsec( INACTIVE_INTERVAL_MSEC );
    267335
    268336        getPasswordFile( server, passwd, sizeof( passwd ) );
     
    585653
    586654    stopServer( s );
    587     evbuffer_free( s->in );
    588     evbuffer_free( s->out );
    589655    tr_free( s->acl );
    590656    tr_free( s );
     
    614680    s->session = session;
    615681    s->port = port;
    616     s->in = evbuffer_new( );
    617     s->out = evbuffer_new( );
    618682    s->acl = tr_strdup( acl );
    619683    s->username = tr_strdup( username );
Note: See TracChangeset for help on using the changeset viewer.