Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(93)

Side by Side Diff: libcurl_http_fetcher.cc

Issue 3010009: AU: When server dies, don't retry forever (Closed) Base URL: ssh://git@chromiumos-git/update_engine.git
Patch Set: fixes for review, cleanup some LOG messages Created 10 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « libcurl_http_fetcher.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2009 The Chromium OS Authors. All rights reserved. 1 // Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "update_engine/libcurl_http_fetcher.h" 5 #include "update_engine/libcurl_http_fetcher.h"
6 #include <algorithm> 6 #include <algorithm>
7 #include "chromeos/obsolete_logging.h" 7 #include "chromeos/obsolete_logging.h"
8 8
9 using std::max; 9 using std::max;
10 using std::make_pair; 10 using std::make_pair;
11 11
12 // This is a concrete implementation of HttpFetcher that uses libcurl to do the 12 // This is a concrete implementation of HttpFetcher that uses libcurl to do the
13 // http work. 13 // http work.
14 14
15 namespace chromeos_update_engine { 15 namespace chromeos_update_engine {
16 16
17 namespace {
18 const int kMaxRetriesCount = 20;
19 }
20
17 LibcurlHttpFetcher::~LibcurlHttpFetcher() { 21 LibcurlHttpFetcher::~LibcurlHttpFetcher() {
18 CleanUp(); 22 CleanUp();
19 } 23 }
20 24
21 void LibcurlHttpFetcher::ResumeTransfer(const std::string& url) { 25 void LibcurlHttpFetcher::ResumeTransfer(const std::string& url) {
22 LOG(INFO) << "Starting/Resuming transfer"; 26 LOG(INFO) << "Starting/Resuming transfer";
23 CHECK(!transfer_in_progress_); 27 CHECK(!transfer_in_progress_);
24 url_ = url; 28 url_ = url;
25 curl_multi_handle_ = curl_multi_init(); 29 curl_multi_handle_ = curl_multi_init();
26 CHECK(curl_multi_handle_); 30 CHECK(curl_multi_handle_);
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
59 63
60 CHECK_EQ(curl_multi_add_handle(curl_multi_handle_, curl_handle_), CURLM_OK); 64 CHECK_EQ(curl_multi_add_handle(curl_multi_handle_, curl_handle_), CURLM_OK);
61 transfer_in_progress_ = true; 65 transfer_in_progress_ = true;
62 } 66 }
63 67
64 // Begins the transfer, which must not have already been started. 68 // Begins the transfer, which must not have already been started.
65 void LibcurlHttpFetcher::BeginTransfer(const std::string& url) { 69 void LibcurlHttpFetcher::BeginTransfer(const std::string& url) {
66 transfer_size_ = -1; 70 transfer_size_ = -1;
67 bytes_downloaded_ = 0; 71 bytes_downloaded_ = 0;
68 resume_offset_ = 0; 72 resume_offset_ = 0;
69 do { 73 retry_count_ = 0;
70 ResumeTransfer(url); 74 ResumeTransfer(url);
71 } while (CurlPerformOnce()); 75 CurlPerformOnce();
72 } 76 }
73 77
74 void LibcurlHttpFetcher::TerminateTransfer() { 78 void LibcurlHttpFetcher::TerminateTransfer() {
75 CleanUp(); 79 CleanUp();
76 } 80 }
77 81
78 bool LibcurlHttpFetcher::CurlPerformOnce() { 82 bool LibcurlHttpFetcher::CurlPerformOnce() {
petkov 2010/07/16 21:47:45 You could make this method void.
79 CHECK(transfer_in_progress_); 83 CHECK(transfer_in_progress_);
80 int running_handles = 0; 84 int running_handles = 0;
81 CURLMcode retcode = CURLM_CALL_MULTI_PERFORM; 85 CURLMcode retcode = CURLM_CALL_MULTI_PERFORM;
82 86
83 // libcurl may request that we immediately call curl_multi_perform after it 87 // libcurl may request that we immediately call curl_multi_perform after it
84 // returns, so we do. libcurl promises that curl_multi_perform will not block. 88 // returns, so we do. libcurl promises that curl_multi_perform will not block.
85 while (CURLM_CALL_MULTI_PERFORM == retcode) { 89 while (CURLM_CALL_MULTI_PERFORM == retcode) {
86 retcode = curl_multi_perform(curl_multi_handle_, &running_handles); 90 retcode = curl_multi_perform(curl_multi_handle_, &running_handles);
87 } 91 }
88 if (0 == running_handles) { 92 if (0 == running_handles) {
93 long http_response_code = 0;
94 if (curl_easy_getinfo(curl_handle_,
petkov 2010/07/16 21:47:45 This is definitely better than the CHECK_EQ...
95 CURLINFO_RESPONSE_CODE,
96 &http_response_code) == CURLE_OK) {
97 LOG(INFO) << "HTTP response code: " << http_response_code;
98 } else {
99 LOG(ERROR) << "Unable to get http response code.";
100 }
101
89 // we're done! 102 // we're done!
90 CleanUp(); 103 CleanUp();
91 104
92 if ((transfer_size_ >= 0) && (bytes_downloaded_ < transfer_size_)) { 105 if ((transfer_size_ >= 0) && (bytes_downloaded_ < transfer_size_)) {
93 // Need to restart transfer 106 // Need to restart transfer
94 return true; 107 retry_count_++;
108 LOG(INFO) << "Restarting transfer b/c we finished, had downloaded "
109 << bytes_downloaded_ << " bytes, but transfer_size_ is "
110 << transfer_size_ << ". retry_count: " << retry_count_;
111 if (retry_count_ > kMaxRetriesCount) {
112 if (delegate_)
113 delegate_->TransferComplete(this, false); // success
114 } else {
115 g_timeout_add(5 * 1000,
116 &LibcurlHttpFetcher::StaticRetryTimeoutCallback,
117 this);
118 }
119 return false;
95 } else { 120 } else {
96 if (delegate_) { 121 if (delegate_) {
97 delegate_->TransferComplete(this, true); // success 122 // success is when http_response_code is 200
123 delegate_->TransferComplete(this, http_response_code == 200);
98 } 124 }
99 } 125 }
100 } else { 126 } else {
101 // set up callback 127 // set up callback
102 SetupMainloopSources(); 128 SetupMainloopSources();
103 } 129 }
104 return false; 130 return false;
105 } 131 }
106 132
107 size_t LibcurlHttpFetcher::LibcurlWrite(void *ptr, size_t size, size_t nmemb) { 133 size_t LibcurlHttpFetcher::LibcurlWrite(void *ptr, size_t size, size_t nmemb) {
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
210 static int counter = 0; 236 static int counter = 0;
211 counter++; 237 counter++;
212 if (counter % 50 == 0) { 238 if (counter % 50 == 0) {
213 LOG(INFO) << "counter = " << counter; 239 LOG(INFO) << "counter = " << counter;
214 } 240 }
215 } 241 }
216 } 242 }
217 243
218 bool LibcurlHttpFetcher::FDCallback(GIOChannel *source, 244 bool LibcurlHttpFetcher::FDCallback(GIOChannel *source,
219 GIOCondition condition) { 245 GIOCondition condition) {
220 while (CurlPerformOnce()) { 246 CurlPerformOnce();
221 ResumeTransfer(url_);
222 }
223 // We handle removing of this source elsewhere, so we always return true. 247 // We handle removing of this source elsewhere, so we always return true.
224 // The docs say, "the function should return FALSE if the event source 248 // The docs say, "the function should return FALSE if the event source
225 // should be removed." 249 // should be removed."
226 // http://www.gtk.org/api/2.6/glib/glib-IO-Channels.html#GIOFunc 250 // http://www.gtk.org/api/2.6/glib/glib-IO-Channels.html#GIOFunc
227 return true; 251 return true;
228 } 252 }
229 253
254 gboolean LibcurlHttpFetcher::RetryTimeoutCallback() {
255 ResumeTransfer(url_);
256 CurlPerformOnce();
257 return FALSE; // Don't have glib auto call this callback again
258 }
259
230 gboolean LibcurlHttpFetcher::TimeoutCallback() { 260 gboolean LibcurlHttpFetcher::TimeoutCallback() {
231 if (!transfer_in_progress_) 261 if (!transfer_in_progress_)
232 return TRUE; 262 return TRUE;
233 // Since we will return false from this function, which tells glib to 263 // Since we will return false from this function, which tells glib to
petkov 2010/07/16 21:47:45 Actually, it seems we're returning TRUE from this
234 // destroy the timeout callback, we must NULL it out here. This way, when 264 // destroy the timeout callback, we must NULL it out here. This way, when
235 // setting up callback sources again, we won't try to delete this (doomed) 265 // setting up callback sources again, we won't try to delete this (doomed)
236 // timeout callback then. 266 // timeout callback then.
237 // TODO(adlr): optimize by checking if we can keep this timeout callback. 267 // TODO(adlr): optimize by checking if we can keep this timeout callback.
238 //timeout_source_ = NULL; 268 //timeout_source_ = NULL;
239 while (CurlPerformOnce()) { 269 CurlPerformOnce();
240 ResumeTransfer(url_);
241 }
242 return TRUE; 270 return TRUE;
243 } 271 }
244 272
245 void LibcurlHttpFetcher::CleanUp() { 273 void LibcurlHttpFetcher::CleanUp() {
246 if (timeout_source_) { 274 if (timeout_source_) {
247 g_source_destroy(timeout_source_); 275 g_source_destroy(timeout_source_);
248 timeout_source_ = NULL; 276 timeout_source_ = NULL;
249 } 277 }
250 278
251 for (IOChannels::iterator it = io_channels_.begin(); 279 for (IOChannels::iterator it = io_channels_.begin();
(...skipping 12 matching lines...) Expand all
264 curl_handle_ = NULL; 292 curl_handle_ = NULL;
265 } 293 }
266 if (curl_multi_handle_) { 294 if (curl_multi_handle_) {
267 CHECK_EQ(curl_multi_cleanup(curl_multi_handle_), CURLM_OK); 295 CHECK_EQ(curl_multi_cleanup(curl_multi_handle_), CURLM_OK);
268 curl_multi_handle_ = NULL; 296 curl_multi_handle_ = NULL;
269 } 297 }
270 transfer_in_progress_ = false; 298 transfer_in_progress_ = false;
271 } 299 }
272 300
273 } // namespace chromeos_update_engine 301 } // namespace chromeos_update_engine
OLDNEW
« no previous file with comments | « libcurl_http_fetcher.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698