source: trunk/libtransmission/webseed.c @ 11599

Last change on this file since 11599 was 11599, checked in by charles, 11 years ago

(trunk) Join the 21st century and use only 1 space at the end sentences. This commit is nearly as important as the semi-annual ones that remove trailing spaces from the ends of lines of code... :)

  • Property svn:keywords set to Date Rev Author Id
File size: 6.7 KB
Line 
1/*
2 * This file Copyright (C) 2008-2010 Mnemosyne LLC
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: webseed.c 11599 2010-12-27 19:18:17Z charles $
11 */
12
13#include <string.h> /* strlen */
14
15#include <event2/buffer.h>
16
17#include "transmission.h"
18#include "inout.h"
19#include "ratecontrol.h"
20#include "torrent.h"
21#include "utils.h"
22#include "web.h"
23#include "webseed.h"
24
25struct tr_webseed
26{
27    tr_bool             busy;
28    tr_bool             dead;
29
30    uint8_t             hash[SHA_DIGEST_LENGTH];
31
32    char              * url;
33
34    tr_peer_callback  * callback;
35    void              * callback_data;
36
37    tr_piece_index_t    pieceIndex;
38    uint32_t            pieceOffset;
39    uint32_t            byteCount;
40
41    tr_ratecontrol      rateDown;
42
43    tr_session        * session;
44
45    struct evbuffer   * content;
46};
47
48/***
49****
50***/
51
52static const tr_peer_event blankEvent = { 0, 0, 0, 0, 0.0f, 0, 0, 0 };
53
54static void
55publish( tr_webseed * w, tr_peer_event * e )
56{
57    if( w->callback != NULL )
58        w->callback( NULL, e, w->callback_data );
59}
60
61static void
62fireNeedReq( tr_webseed * w )
63{
64#if 0
65    tr_peer_event e = blankEvent;
66    e.eventType = TR_PEER_NEED_REQ;
67    publish( w, &e );
68#endif
69}
70
71static void
72fireClientGotBlock( tr_webseed * w, uint32_t pieceIndex, uint32_t offset, uint32_t length )
73{
74    tr_peer_event e = blankEvent;
75    e.eventType = TR_PEER_CLIENT_GOT_BLOCK;
76    e.pieceIndex = pieceIndex;
77    e.offset = offset;
78    e.length = length;
79    publish( w, &e );
80}
81
82static void
83fireClientGotData( tr_webseed * w, uint32_t length )
84{
85    tr_peer_event e = blankEvent;
86    e.eventType = TR_PEER_CLIENT_GOT_DATA;
87    e.length = length;
88    e.wasPieceData = TRUE;
89    publish( w, &e );
90}
91
92/***
93****
94***/
95
96static char*
97makeURL( tr_webseed *    w,
98         const tr_file * file )
99{
100    struct evbuffer * out = evbuffer_new( );
101    const char *      url = w->url;
102    const size_t      url_len = strlen( url );
103
104    evbuffer_add( out, url, url_len );
105
106    /* if url ends with a '/', add the torrent name */
107    if( url[url_len - 1] == '/' && file->name )
108        tr_http_escape( out, file->name, strlen(file->name), FALSE );
109
110    return evbuffer_free_to_str( out );
111}
112
113static void requestNextChunk( tr_webseed * w );
114
115static void
116webResponseFunc( tr_session    * session,
117                 long            response_code,
118                 const void    * response,
119                 size_t          response_byte_count,
120                 void          * vw )
121{
122    tr_webseed * w = vw;
123    tr_torrent * tor = tr_torrentFindFromHash( session, w->hash );
124    const int    success = ( response_code == 206 );
125
126/*fprintf( stderr, "server responded with code %ld and %lu bytes\n",
127  response_code, (unsigned long)response_byte_count );*/
128    if( !success )
129    {
130        /* FIXME */
131    }
132    else if( tor != NULL )
133    {
134        evbuffer_add( w->content, response, response_byte_count );
135        if( !w->dead )
136        {
137            fireClientGotData( w, response_byte_count );
138            tr_rcTransferred( &w->rateDown, response_byte_count );
139        }
140
141        if( evbuffer_get_length( w->content ) < w->byteCount )
142            requestNextChunk( w );
143        else {
144            tr_ioWrite( tor, w->pieceIndex, w->pieceOffset, w->byteCount, evbuffer_pullup( w->content, -1 ) );
145            evbuffer_drain( w->content, evbuffer_get_length( w->content ) );
146            w->busy = 0;
147            if( w->dead )
148                tr_webseedFree( w );
149            else  {
150                fireClientGotBlock( w, w->pieceIndex, w->pieceOffset, w->byteCount );
151                fireNeedReq( w );
152            }
153        }
154    }
155}
156
157static void
158requestNextChunk( tr_webseed * w )
159{
160    tr_torrent * tor = tr_torrentFindFromHash( w->session, w->hash );
161
162    if( tor != NULL )
163    {
164        const tr_info * inf = tr_torrentInfo( tor );
165        const uint32_t have = evbuffer_get_length( w->content );
166        const uint32_t left = w->byteCount - have;
167        const uint32_t pieceOffset = w->pieceOffset + have;
168        tr_file_index_t fileIndex;
169        uint64_t fileOffset;
170        uint32_t thisPass;
171        char * url;
172        char * range;
173
174        tr_ioFindFileLocation( tor, w->pieceIndex, pieceOffset,
175                               &fileIndex, &fileOffset );
176        thisPass = MIN( left, inf->files[fileIndex].length - fileOffset );
177
178        url = makeURL( w, &inf->files[fileIndex] );
179/*fprintf( stderr, "url is [%s]\n", url );*/
180        range = tr_strdup_printf( "%"PRIu64"-%"PRIu64, fileOffset, fileOffset + thisPass - 1 );
181/*fprintf( stderr, "range is [%s] ... we want %lu total, we have %lu, so %lu are left, and we're asking for %lu this time\n", range, (unsigned long)w->byteCount, (unsigned long)have, (unsigned long)left, (unsigned long)thisPass );*/
182        tr_webRun( w->session, url, range, webResponseFunc, w );
183        tr_free( range );
184        tr_free( url );
185    }
186}
187
188tr_addreq_t
189tr_webseedAddRequest( tr_webseed  * w,
190                      uint32_t      pieceIndex,
191                      uint32_t      pieceOffset,
192                      uint32_t      byteCount )
193{
194    int ret;
195
196    if( w->busy || w->dead )
197    {
198        ret = TR_ADDREQ_FULL;
199    }
200    else
201    {
202        w->busy = 1;
203        w->pieceIndex = pieceIndex;
204        w->pieceOffset = pieceOffset;
205        w->byteCount = byteCount;
206        evbuffer_drain( w->content, evbuffer_get_length( w->content ) );
207        requestNextChunk( w );
208        ret = TR_ADDREQ_OK;
209    }
210
211    return ret;
212}
213
214int
215tr_webseedIsActive( const tr_webseed * w )
216{
217    return w->busy != 0;
218}
219
220int
221tr_webseedGetSpeed_Bps( const tr_webseed * w, uint64_t now, int * setme_Bps )
222{
223    const int isActive = tr_webseedIsActive( w );
224    *setme_Bps = isActive ? tr_rcRate_Bps( &w->rateDown, now ) : 0;
225    return isActive;
226}
227
228/***
229****
230***/
231
232tr_webseed*
233tr_webseedNew( struct tr_torrent * torrent,
234               const char        * url,
235               tr_peer_callback  * callback,
236               void              * callback_data )
237{
238    tr_webseed * w = tr_new0( tr_webseed, 1 );
239
240    memcpy( w->hash, torrent->info.hash, SHA_DIGEST_LENGTH );
241    w->session = torrent->session;
242    w->content = evbuffer_new( );
243    w->url = tr_strdup( url );
244    w->callback = callback;
245    w->callback_data = callback_data;
246    tr_rcConstruct( &w->rateDown );
247    return w;
248}
249
250void
251tr_webseedFree( tr_webseed * w )
252{
253    if( w )
254    {
255        if( w->busy )
256        {
257            w->dead = 1;
258        }
259        else
260        {
261            evbuffer_free( w->content );
262            tr_rcDestruct( &w->rateDown );
263            tr_free( w->url );
264            tr_free( w );
265        }
266    }
267}
Note: See TracBrowser for help on using the repository browser.