~ubuntu-branches/ubuntu/quantal/aria2/quantal

« back to all changes in this revision

Viewing changes to src/DownloadCommand.cc

  • Committer: Bazaar Package Importer
  • Author(s): Kartik Mistry
  • Date: 2011-04-02 12:38:55 UTC
  • mfrom: (2.5.2 sid)
  • Revision ID: james.westby@ubuntu.com-20110402123855-znkslovhf5qvkjut
Tags: 1.11.1-1
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
61
61
#include "wallclock.h"
62
62
#include "SinkStreamFilter.h"
63
63
#include "FileEntry.h"
 
64
#include "SocketRecvBuffer.h"
64
65
#ifdef ENABLE_MESSAGE_DIGEST
65
66
# include "MessageDigest.h"
66
 
# include "MessageDigestHelper.h"
 
67
# include "message_digest_helper.h"
67
68
#endif // ENABLE_MESSAGE_DIGEST
68
69
#ifdef ENABLE_BITTORRENT
69
70
# include "bittorrent_helper.h"
75
76
const size_t BUFSIZE = 16*1024;
76
77
} // namespace
77
78
 
78
 
DownloadCommand::DownloadCommand(cuid_t cuid,
79
 
                                 const SharedHandle<Request>& req,
80
 
                                 const SharedHandle<FileEntry>& fileEntry,
81
 
                                 RequestGroup* requestGroup,
82
 
                                 DownloadEngine* e,
83
 
                                 const SocketHandle& s):
84
 
  AbstractCommand(cuid, req, fileEntry, requestGroup, e, s),
85
 
  startupIdleTime_(10),
86
 
  lowestDownloadSpeedLimit_(0),
87
 
  pieceHashValidationEnabled_(false)
 
79
DownloadCommand::DownloadCommand
 
80
(cuid_t cuid,
 
81
 const SharedHandle<Request>& req,
 
82
 const SharedHandle<FileEntry>& fileEntry,
 
83
 RequestGroup* requestGroup,
 
84
 DownloadEngine* e,
 
85
 const SocketHandle& s,
 
86
 const SharedHandle<SocketRecvBuffer>& socketRecvBuffer)
 
87
  : AbstractCommand(cuid, req, fileEntry, requestGroup, e, s, socketRecvBuffer),
 
88
    startupIdleTime_(10),
 
89
    lowestDownloadSpeedLimit_(0),
 
90
    pieceHashValidationEnabled_(false)
88
91
{
89
92
#ifdef ENABLE_MESSAGE_DIGEST
90
93
  {
105
108
  streamFilter_.reset(new SinkStreamFilter(pieceHashValidationEnabled_));
106
109
  streamFilter_->init();
107
110
  sinkFilterOnly_ = true;
 
111
  checkSocketRecvBuffer();
108
112
}
109
113
 
110
114
DownloadCommand::~DownloadCommand() {
124
128
  const SharedHandle<DiskAdaptor>& diskAdaptor =
125
129
    getPieceStorage()->getDiskAdaptor();
126
130
  SharedHandle<Segment> segment = getSegments().front();
127
 
  size_t bufSize;
128
 
  unsigned char buf[BUFSIZE];
129
 
  if(sinkFilterOnly_) {
130
 
    if(segment->getLength() > 0 ) {
131
 
      if(static_cast<uint64_t>(segment->getPosition()+segment->getLength()) <=
132
 
         static_cast<uint64_t>(getFileEntry()->getLastOffset())) {
133
 
        bufSize = std::min(segment->getLength()-segment->getWrittenLength(),
134
 
                           BUFSIZE);
 
131
  bool eof = false;
 
132
  if(getSocketRecvBuffer()->bufferEmpty()) {
 
133
    // Only read from socket when buffer is empty.  Imagine that When
 
134
    // segment length is *short* and we are using HTTP pilelining.  We
 
135
    // issued 2 requests in pipeline. When reading first response
 
136
    // header, we may read its response body and 2nd response header
 
137
    // and 2nd response body in buffer if they are small enough to fit
 
138
    // in buffer. And then server may sends EOF.  In this case, we
 
139
    // read data from socket here, we will get EOF and leaves 2nd
 
140
    // response unprocessed.  To prevent this, we don't read from
 
141
    // socket when buffer is not empty.
 
142
    eof = getSocketRecvBuffer()->recv() == 0 &&
 
143
      !getSocket()->wantRead() && !getSocket()->wantWrite();
 
144
  }
 
145
  if(!eof) {
 
146
    size_t bufSize;
 
147
    if(sinkFilterOnly_) {
 
148
      if(segment->getLength() > 0) {
 
149
        if(static_cast<uint64_t>(segment->getPosition()+segment->getLength()) <=
 
150
           static_cast<uint64_t>(getFileEntry()->getLastOffset())) {
 
151
          bufSize = std::min(segment->getLength()-segment->getWrittenLength(),
 
152
                             getSocketRecvBuffer()->getBufferLength());
 
153
        } else {
 
154
          bufSize =
 
155
            std::min
 
156
            (static_cast<size_t>
 
157
             (getFileEntry()->getLastOffset()-segment->getPositionToWrite()),
 
158
             getSocketRecvBuffer()->getBufferLength());
 
159
        }
135
160
      } else {
136
 
        bufSize =
137
 
          std::min
138
 
          (static_cast<size_t>
139
 
           (getFileEntry()->getLastOffset()-segment->getPositionToWrite()),
140
 
           BUFSIZE);
 
161
        bufSize = getSocketRecvBuffer()->getBufferLength();
141
162
      }
 
163
      streamFilter_->transform(diskAdaptor, segment,
 
164
                               getSocketRecvBuffer()->getBuffer(), bufSize);
142
165
    } else {
143
 
      bufSize = BUFSIZE;
 
166
      // It is possible that segment is completed but we have some bytes
 
167
      // of stream to read. For example, chunked encoding has "0"+CRLF
 
168
      // after data. After we read data(at this moment segment is
 
169
      // completed), we need another 3bytes(or more if it has trailers).
 
170
      streamFilter_->transform(diskAdaptor, segment,
 
171
                               getSocketRecvBuffer()->getBuffer(),
 
172
                               getSocketRecvBuffer()->getBufferLength());
 
173
      bufSize = streamFilter_->getBytesProcessed();
144
174
    }
145
 
    getSocket()->readData(buf, bufSize);
146
 
    streamFilter_->transform(diskAdaptor, segment, buf, bufSize);
147
 
  } else {
148
 
    // It is possible that segment is completed but we have some bytes
149
 
    // of stream to read. For example, chunked encoding has "0"+CRLF
150
 
    // after data. After we read data(at this moment segment is
151
 
    // completed), we need another 3bytes(or more if it has trailers).
152
 
    bufSize = BUFSIZE;
153
 
    getSocket()->peekData(buf, bufSize);
154
 
    streamFilter_->transform(diskAdaptor, segment, buf, bufSize);
155
 
    bufSize = streamFilter_->getBytesProcessed();
156
 
    getSocket()->readData(buf, bufSize);
 
175
    getSocketRecvBuffer()->shiftBuffer(bufSize);
 
176
    peerStat_->updateDownloadLength(bufSize);
157
177
  }
158
 
  peerStat_->updateDownloadLength(bufSize);
159
178
  getSegmentMan()->updateDownloadSpeedFor(peerStat_);
160
179
  bool segmentPartComplete = false;
161
180
  // Note that GrowSegment::complete() always returns false.
163
182
    if(segment->complete() ||
164
183
       segment->getPositionToWrite() == getFileEntry()->getLastOffset()) {
165
184
      segmentPartComplete = true;
166
 
    } else if(segment->getLength() == 0 && bufSize == 0 &&
167
 
              !getSocket()->wantRead() && !getSocket()->wantWrite()) {
 
185
    } else if(segment->getLength() == 0 && eof) {
168
186
      segmentPartComplete = true;
169
187
    }
170
188
  } else {
187
205
    }
188
206
  }
189
207
 
190
 
  if(!segmentPartComplete && bufSize == 0 &&
191
 
     !getSocket()->wantRead() && !getSocket()->wantWrite()) {
 
208
  if(!segmentPartComplete && eof) {
192
209
    throw DL_RETRY_EX(EX_GOT_EOF);
193
210
  }
194
211
 
219
236
            messageDigest_->reset();
220
237
            validatePieceHash
221
238
              (segment, expectedPieceHash,
222
 
               MessageDigestHelper::hexDigest
 
239
               message_digest::hexDigest
223
240
               (messageDigest_,
224
241
                getPieceStorage()->getDiskAdaptor(),
225
242
                segment->getPosition(),
245
262
  } else {
246
263
    checkLowestDownloadSpeed();
247
264
    setWriteCheckSocketIf(getSocket(), getSocket()->wantWrite());
 
265
    checkSocketRecvBuffer();
248
266
    getDownloadEngine()->addCommand(this);
249
267
    return false;
250
268
  }
288
306
        getDownloadEngine()->getCheckIntegrityMan()->pushEntry(entry);
289
307
      }
290
308
    }
 
309
#endif // ENABLE_MESSAGE_DIGEST
291
310
    // Following 2lines are needed for DownloadEngine to detect
292
311
    // completed RequestGroups without 1sec delay.
293
312
    getDownloadEngine()->setNoWait(true);
294
313
    getDownloadEngine()->setRefreshInterval(0);
295
 
#endif // ENABLE_MESSAGE_DIGEST
296
314
    return true;
297
315
  } else {
298
316
    // The number of segments should be 1 in order to pass through the next
319
337
        // nextSegment->getWrittenLength() corrupts file.
320
338
        return prepareForRetry(0);
321
339
      } else {
 
340
        checkSocketRecvBuffer();
322
341
        getDownloadEngine()->addCommand(this);
323
342
        return false;
324
343
      }