| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "base/bind.h" | |
| 6 #include "base/bind_helpers.h" | |
| 7 #include "base/file_path.h" | |
| 8 #include "base/logging.h" | |
| 9 #include "base/memory/scoped_ptr.h" | |
| 10 #include "base/message_loop.h" | |
| 11 #include "base/string_number_conversions.h" | |
| 12 #include "base/string_util.h" | |
| 13 #include "base/threading/thread.h" | |
| 14 #include "base/win/scoped_handle.h" | |
| 15 #include "googleurl/src/gurl.h" | |
| 16 #include "net/base/io_buffer.h" | |
| 17 #include "net/base/net_errors.h" | |
| 18 #include "net/base/test_completion_callback.h" | |
| 19 #include "net/disk_cache/backend_impl.h" | |
| 20 #include "net/disk_cache/entry_impl.h" | |
| 21 #include "net/http/http_cache.h" | |
| 22 #include "net/http/http_response_headers.h" | |
| 23 #include "net/http/http_response_info.h" | |
| 24 #include "net/tools/dump_cache/cache_dumper.h" | |
| 25 | |
| 26 namespace { | |
| 27 | |
| 28 const wchar_t kPipePrefix[] = L"\\\\.\\pipe\\dump_cache_"; | |
| 29 const int kChannelSize = 64 * 1024; | |
| 30 const int kNumStreams = 4; | |
| 31 | |
| 32 // Simple macro to print out formatted debug messages. It is similar to a DLOG | |
| 33 // except that it doesn't include a header. | |
| 34 #ifdef NDEBUG | |
| 35 #define DEBUGMSG(...) {} | |
| 36 #else | |
| 37 #define DEBUGMSG(...) { printf(__VA_ARGS__); } | |
| 38 #endif | |
| 39 | |
| 40 HANDLE OpenServer(const std::wstring& pipe_number) { | |
| 41 std::wstring pipe_name(kPipePrefix); | |
| 42 pipe_name.append(pipe_number); | |
| 43 return CreateFile(pipe_name.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, | |
| 44 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); | |
| 45 } | |
| 46 | |
| 47 // This is the basic message to use between the two processes. It is intended | |
| 48 // to transmit a single action (like "get the key name for entry xx"), with up | |
| 49 // to 5 32-bit arguments and 4 64-bit arguments. After this structure, the rest | |
| 50 // of the message has |buffer_bytes| of length with the actual data. | |
| 51 struct Message { | |
| 52 int32 command; | |
| 53 int32 result; | |
| 54 int32 buffer_bytes; | |
| 55 int32 arg1; | |
| 56 int32 arg2; | |
| 57 int32 arg3; | |
| 58 int32 arg4; | |
| 59 int32 arg5; | |
| 60 int64 long_arg1; | |
| 61 int64 long_arg2; | |
| 62 int64 long_arg3; | |
| 63 int64 long_arg4; | |
| 64 Message() { | |
| 65 memset(this, 0, sizeof(*this)); | |
| 66 } | |
| 67 Message& operator= (const Message& other) { | |
| 68 memcpy(this, &other, sizeof(*this)); | |
| 69 return *this; | |
| 70 } | |
| 71 }; | |
| 72 | |
| 73 const int kBufferSize = kChannelSize - sizeof(Message); | |
| 74 struct IoBuffer { | |
| 75 Message msg; | |
| 76 char buffer[kBufferSize]; | |
| 77 }; | |
| 78 COMPILE_ASSERT(sizeof(IoBuffer) == kChannelSize, invalid_io_buffer); | |
| 79 | |
| 80 | |
| 81 // The list of commands. | |
| 82 // Currently, there is support for working ONLY with one entry at a time. | |
| 83 enum { | |
| 84 // Get the entry from list |arg1| that follows |long_arg1|. | |
| 85 // The result is placed on |long_arg1| (closes the previous one). | |
| 86 GET_NEXT_ENTRY = 1, | |
| 87 // Get the entry from list |arg1| that precedes |long_arg1|. | |
| 88 // The result is placed on |long_arg1| (closes the previous one). | |
| 89 GET_PREV_ENTRY, | |
| 90 // Closes the entry |long_arg1|. | |
| 91 CLOSE_ENTRY, | |
| 92 // Get the key of the entry |long_arg1|. | |
| 93 GET_KEY, | |
| 94 // Get last used (long_arg2) and last modified (long_arg3) times for the | |
| 95 // entry at |long_arg1|. | |
| 96 GET_USE_TIMES, | |
| 97 // Returns on |arg2| the data size in bytes if the stream |arg1| of entry at | |
| 98 // |long_arg1|. | |
| 99 GET_DATA_SIZE, | |
| 100 // Returns |arg2| bytes of the stream |arg1| for the entry at |long_arg1|, | |
| 101 // starting at offset |arg3|. | |
| 102 READ_DATA, | |
| 103 // End processing requests. | |
| 104 QUIT | |
| 105 }; | |
| 106 | |
| 107 // The list of return codes. | |
| 108 enum { | |
| 109 RESULT_OK = 0, | |
| 110 RESULT_UNKNOWN_COMMAND, | |
| 111 RESULT_INVALID_PARAMETER, | |
| 112 RESULT_NAME_OVERFLOW, | |
| 113 RESULT_PENDING // This error code is NOT expected by the master process. | |
| 114 }; | |
| 115 | |
| 116 // ----------------------------------------------------------------------- | |
| 117 | |
| 118 class BaseSM : public MessageLoopForIO::IOHandler { | |
| 119 public: | |
| 120 explicit BaseSM(HANDLE channel); | |
| 121 virtual ~BaseSM(); | |
| 122 | |
| 123 protected: | |
| 124 bool SendMsg(const Message& msg); | |
| 125 bool ReceiveMsg(); | |
| 126 bool ConnectChannel(); | |
| 127 bool IsPending(); | |
| 128 | |
| 129 MessageLoopForIO::IOContext in_context_; | |
| 130 MessageLoopForIO::IOContext out_context_; | |
| 131 disk_cache::EntryImpl* entry_; | |
| 132 HANDLE channel_; | |
| 133 int state_; | |
| 134 int pending_count_; | |
| 135 scoped_array<char> in_buffer_; | |
| 136 scoped_array<char> out_buffer_; | |
| 137 IoBuffer* input_; | |
| 138 IoBuffer* output_; | |
| 139 base::Thread cache_thread_; | |
| 140 | |
| 141 DISALLOW_COPY_AND_ASSIGN(BaseSM); | |
| 142 }; | |
| 143 | |
| 144 BaseSM::BaseSM(HANDLE channel) | |
| 145 : entry_(NULL), channel_(channel), state_(0), pending_count_(0), | |
| 146 cache_thread_("cache") { | |
| 147 in_buffer_.reset(new char[kChannelSize]); | |
| 148 out_buffer_.reset(new char[kChannelSize]); | |
| 149 input_ = reinterpret_cast<IoBuffer*>(in_buffer_.get()); | |
| 150 output_ = reinterpret_cast<IoBuffer*>(out_buffer_.get()); | |
| 151 | |
| 152 memset(&in_context_, 0, sizeof(in_context_)); | |
| 153 memset(&out_context_, 0, sizeof(out_context_)); | |
| 154 in_context_.handler = this; | |
| 155 out_context_.handler = this; | |
| 156 MessageLoopForIO::current()->RegisterIOHandler(channel_, this); | |
| 157 CHECK(cache_thread_.StartWithOptions( | |
| 158 base::Thread::Options(MessageLoop::TYPE_IO, 0))); | |
| 159 } | |
| 160 | |
| 161 BaseSM::~BaseSM() { | |
| 162 if (entry_) | |
| 163 entry_->Close(); | |
| 164 } | |
| 165 | |
| 166 bool BaseSM::SendMsg(const Message& msg) { | |
| 167 // Only one command will be in-flight at a time. Let's start the Read IO here | |
| 168 // when we know that it will be pending. | |
| 169 if (!ReceiveMsg()) | |
| 170 return false; | |
| 171 | |
| 172 output_->msg = msg; | |
| 173 DWORD written; | |
| 174 if (!WriteFile(channel_, output_, sizeof(msg) + msg.buffer_bytes, &written, | |
| 175 &out_context_.overlapped)) { | |
| 176 if (ERROR_IO_PENDING != GetLastError()) | |
| 177 return false; | |
| 178 } | |
| 179 pending_count_++; | |
| 180 return true; | |
| 181 } | |
| 182 | |
| 183 bool BaseSM::ReceiveMsg() { | |
| 184 DWORD read; | |
| 185 if (!ReadFile(channel_, input_, kChannelSize, &read, | |
| 186 &in_context_.overlapped)) { | |
| 187 if (ERROR_IO_PENDING != GetLastError()) | |
| 188 return false; | |
| 189 } | |
| 190 pending_count_++; | |
| 191 return true; | |
| 192 } | |
| 193 | |
| 194 bool BaseSM::ConnectChannel() { | |
| 195 if (!ConnectNamedPipe(channel_, &in_context_.overlapped)) { | |
| 196 DWORD error = GetLastError(); | |
| 197 if (ERROR_PIPE_CONNECTED == error) | |
| 198 return true; | |
| 199 // By returning true in case of a generic error, we allow the operation to | |
| 200 // fail while sending the first message. | |
| 201 if (ERROR_IO_PENDING != error) | |
| 202 return true; | |
| 203 } | |
| 204 pending_count_++; | |
| 205 return false; | |
| 206 } | |
| 207 | |
| 208 bool BaseSM::IsPending() { | |
| 209 return pending_count_ != 0; | |
| 210 } | |
| 211 | |
| 212 // ----------------------------------------------------------------------- | |
| 213 | |
| 214 class MasterSM : public BaseSM { | |
| 215 public: | |
| 216 MasterSM(const FilePath& path, HANDLE channel, bool dump_to_disk) | |
| 217 : BaseSM(channel), | |
| 218 path_(path), | |
| 219 dump_to_disk_(dump_to_disk) { | |
| 220 } | |
| 221 virtual ~MasterSM() { | |
| 222 delete writer_; | |
| 223 } | |
| 224 | |
| 225 bool DoInit(); | |
| 226 virtual void OnIOCompleted(MessageLoopForIO::IOContext* context, | |
| 227 DWORD bytes_transfered, DWORD error); | |
| 228 | |
| 229 private: | |
| 230 enum { | |
| 231 MASTER_INITIAL = 0, | |
| 232 MASTER_CONNECT, | |
| 233 MASTER_GET_ENTRY, | |
| 234 MASTER_GET_NEXT_ENTRY, | |
| 235 MASTER_GET_KEY, | |
| 236 MASTER_GET_USE_TIMES, | |
| 237 MASTER_GET_DATA_SIZE, | |
| 238 MASTER_READ_DATA, | |
| 239 MASTER_END | |
| 240 }; | |
| 241 | |
| 242 void SendGetPrevEntry(); | |
| 243 void DoGetEntry(); | |
| 244 void DoGetKey(int bytes_read); | |
| 245 void DoCreateEntryComplete(int result); | |
| 246 void DoGetUseTimes(); | |
| 247 void SendGetDataSize(); | |
| 248 void DoGetDataSize(); | |
| 249 void CloseEntry(); | |
| 250 void SendReadData(); | |
| 251 void DoReadData(int bytes_read); | |
| 252 void DoReadDataComplete(int ret); | |
| 253 void SendQuit(); | |
| 254 void DoEnd(); | |
| 255 void Fail(); | |
| 256 | |
| 257 base::Time last_used_; | |
| 258 base::Time last_modified_; | |
| 259 int64 remote_entry_; | |
| 260 int stream_; | |
| 261 int bytes_remaining_; | |
| 262 int offset_; | |
| 263 int copied_entries_; | |
| 264 int read_size_; | |
| 265 scoped_ptr<disk_cache::Backend> cache_; | |
| 266 CacheDumpWriter* writer_; | |
| 267 const FilePath path_; | |
| 268 bool dump_to_disk_; | |
| 269 }; | |
| 270 | |
| 271 void MasterSM::OnIOCompleted(MessageLoopForIO::IOContext* context, | |
| 272 DWORD bytes_transfered, DWORD error) { | |
| 273 pending_count_--; | |
| 274 if (context == &out_context_) { | |
| 275 if (!error) | |
| 276 return; | |
| 277 return Fail(); | |
| 278 } | |
| 279 | |
| 280 int bytes_read = static_cast<int>(bytes_transfered); | |
| 281 if (bytes_read < sizeof(Message) && state_ != MASTER_END && | |
| 282 state_ != MASTER_CONNECT) { | |
| 283 printf("Communication breakdown\n"); | |
| 284 return Fail(); | |
| 285 } | |
| 286 | |
| 287 switch (state_) { | |
| 288 case MASTER_CONNECT: | |
| 289 SendGetPrevEntry(); | |
| 290 break; | |
| 291 case MASTER_GET_ENTRY: | |
| 292 DoGetEntry(); | |
| 293 break; | |
| 294 case MASTER_GET_KEY: | |
| 295 DoGetKey(bytes_read); | |
| 296 break; | |
| 297 case MASTER_GET_USE_TIMES: | |
| 298 DoGetUseTimes(); | |
| 299 break; | |
| 300 case MASTER_GET_DATA_SIZE: | |
| 301 DoGetDataSize(); | |
| 302 break; | |
| 303 case MASTER_READ_DATA: | |
| 304 DoReadData(bytes_read); | |
| 305 break; | |
| 306 case MASTER_END: | |
| 307 if (!IsPending()) | |
| 308 DoEnd(); | |
| 309 break; | |
| 310 default: | |
| 311 NOTREACHED(); | |
| 312 break; | |
| 313 } | |
| 314 } | |
| 315 | |
| 316 bool MasterSM::DoInit() { | |
| 317 DEBUGMSG("Master DoInit\n"); | |
| 318 DCHECK(state_ == MASTER_INITIAL); | |
| 319 | |
| 320 if (dump_to_disk_) { | |
| 321 writer_ = new DiskDumper(path_); | |
| 322 } else { | |
| 323 disk_cache::Backend* cache; | |
| 324 net::TestCompletionCallback cb; | |
| 325 int rv = disk_cache::CreateCacheBackend(net::DISK_CACHE, path_, 0, false, | |
| 326 cache_thread_.message_loop_proxy(), | |
| 327 NULL, &cache, cb.callback()); | |
| 328 if (cb.GetResult(rv) != net::OK) { | |
| 329 printf("Unable to initialize new files\n"); | |
| 330 return false; | |
| 331 } | |
| 332 cache_.reset(cache); | |
| 333 writer_ = new CacheDumper(cache_.get()); | |
| 334 } | |
| 335 if (!writer_) | |
| 336 return false; | |
| 337 | |
| 338 copied_entries_ = 0; | |
| 339 remote_entry_ = 0; | |
| 340 | |
| 341 if (ConnectChannel()) { | |
| 342 SendGetPrevEntry(); | |
| 343 // If we don't have pending operations we couldn't connect. | |
| 344 return IsPending(); | |
| 345 } | |
| 346 | |
| 347 state_ = MASTER_CONNECT; | |
| 348 return true; | |
| 349 } | |
| 350 | |
| 351 void MasterSM::SendGetPrevEntry() { | |
| 352 DEBUGMSG("Master SendGetPrevEntry\n"); | |
| 353 state_ = MASTER_GET_ENTRY; | |
| 354 Message msg; | |
| 355 msg.command = GET_PREV_ENTRY; | |
| 356 msg.long_arg1 = remote_entry_; | |
| 357 SendMsg(msg); | |
| 358 } | |
| 359 | |
| 360 void MasterSM::DoGetEntry() { | |
| 361 DEBUGMSG("Master DoGetEntry\n"); | |
| 362 DCHECK(state_ == MASTER_GET_ENTRY); | |
| 363 DCHECK(input_->msg.command == GET_PREV_ENTRY); | |
| 364 if (input_->msg.result != RESULT_OK) | |
| 365 return Fail(); | |
| 366 | |
| 367 if (!input_->msg.long_arg1) { | |
| 368 printf("Done: %d entries copied over.\n", copied_entries_); | |
| 369 return SendQuit(); | |
| 370 } | |
| 371 remote_entry_ = input_->msg.long_arg1; | |
| 372 state_ = MASTER_GET_KEY; | |
| 373 Message msg; | |
| 374 msg.command = GET_KEY; | |
| 375 msg.long_arg1 = remote_entry_; | |
| 376 SendMsg(msg); | |
| 377 } | |
| 378 | |
| 379 void MasterSM::DoGetKey(int bytes_read) { | |
| 380 DEBUGMSG("Master DoGetKey\n"); | |
| 381 DCHECK(state_ == MASTER_GET_KEY); | |
| 382 DCHECK(input_->msg.command == GET_KEY); | |
| 383 if (input_->msg.result == RESULT_NAME_OVERFLOW) { | |
| 384 // The key is too long. Just move on. | |
| 385 printf("Skipping entry (name too long)\n"); | |
| 386 return SendGetPrevEntry(); | |
| 387 } | |
| 388 | |
| 389 if (input_->msg.result != RESULT_OK) | |
| 390 return Fail(); | |
| 391 | |
| 392 std::string key(input_->buffer); | |
| 393 DCHECK(key.size() == static_cast<size_t>(input_->msg.buffer_bytes - 1)); | |
| 394 | |
| 395 int rv = writer_->CreateEntry( | |
| 396 key, reinterpret_cast<disk_cache::Entry**>(&entry_), | |
| 397 base::Bind(&MasterSM::DoCreateEntryComplete, base::Unretained(this))); | |
| 398 | |
| 399 if (rv != net::ERR_IO_PENDING) | |
| 400 DoCreateEntryComplete(rv); | |
| 401 } | |
| 402 | |
| 403 void MasterSM::DoCreateEntryComplete(int result) { | |
| 404 std::string key(input_->buffer); | |
| 405 if (result != net::OK) { | |
| 406 printf("Skipping entry \"%s\": %d\n", key.c_str(), GetLastError()); | |
| 407 return SendGetPrevEntry(); | |
| 408 } | |
| 409 | |
| 410 if (key.size() >= 64) { | |
| 411 key[60] = '.'; | |
| 412 key[61] = '.'; | |
| 413 key[62] = '.'; | |
| 414 key[63] = '\0'; | |
| 415 } | |
| 416 DEBUGMSG("Entry \"%s\" created\n", key.c_str()); | |
| 417 state_ = MASTER_GET_USE_TIMES; | |
| 418 Message msg; | |
| 419 msg.command = GET_USE_TIMES; | |
| 420 msg.long_arg1 = remote_entry_; | |
| 421 SendMsg(msg); | |
| 422 } | |
| 423 | |
| 424 void MasterSM::DoGetUseTimes() { | |
| 425 DEBUGMSG("Master DoGetUseTimes\n"); | |
| 426 DCHECK(state_ == MASTER_GET_USE_TIMES); | |
| 427 DCHECK(input_->msg.command == GET_USE_TIMES); | |
| 428 if (input_->msg.result != RESULT_OK) | |
| 429 return Fail(); | |
| 430 | |
| 431 last_used_ = base::Time::FromInternalValue(input_->msg.long_arg2); | |
| 432 last_modified_ = base::Time::FromInternalValue(input_->msg.long_arg3); | |
| 433 stream_ = 0; | |
| 434 SendGetDataSize(); | |
| 435 } | |
| 436 | |
| 437 void MasterSM::SendGetDataSize() { | |
| 438 DEBUGMSG("Master SendGetDataSize (%d)\n", stream_); | |
| 439 state_ = MASTER_GET_DATA_SIZE; | |
| 440 Message msg; | |
| 441 msg.command = GET_DATA_SIZE; | |
| 442 msg.arg1 = stream_; | |
| 443 msg.long_arg1 = remote_entry_; | |
| 444 SendMsg(msg); | |
| 445 } | |
| 446 | |
| 447 void MasterSM::DoGetDataSize() { | |
| 448 DEBUGMSG("Master DoGetDataSize: %d\n", input_->msg.arg2); | |
| 449 DCHECK(state_ == MASTER_GET_DATA_SIZE); | |
| 450 DCHECK(input_->msg.command == GET_DATA_SIZE); | |
| 451 if (input_->msg.result == RESULT_INVALID_PARAMETER) | |
| 452 // No more streams, move to the next entry. | |
| 453 return CloseEntry(); | |
| 454 | |
| 455 if (input_->msg.result != RESULT_OK) | |
| 456 return Fail(); | |
| 457 | |
| 458 bytes_remaining_ = input_->msg.arg2; | |
| 459 offset_ = 0; | |
| 460 SendReadData(); | |
| 461 } | |
| 462 | |
| 463 void MasterSM::CloseEntry() { | |
| 464 DEBUGMSG("Master CloseEntry\n"); | |
| 465 printf("%c\r", copied_entries_ % 2 ? 'x' : '+'); | |
| 466 writer_->CloseEntry(entry_, last_used_, last_modified_); | |
| 467 entry_ = NULL; | |
| 468 copied_entries_++; | |
| 469 SendGetPrevEntry(); | |
| 470 } | |
| 471 | |
| 472 void MasterSM::SendReadData() { | |
| 473 int read_size = std::min(bytes_remaining_, kBufferSize); | |
| 474 DEBUGMSG("Master SendReadData (%d): %d bytes at %d\n", stream_, read_size, | |
| 475 offset_); | |
| 476 if (bytes_remaining_ <= 0) { | |
| 477 stream_++; | |
| 478 if (stream_ >= kNumStreams) | |
| 479 return CloseEntry(); | |
| 480 return SendGetDataSize(); | |
| 481 } | |
| 482 | |
| 483 state_ = MASTER_READ_DATA; | |
| 484 Message msg; | |
| 485 msg.command = READ_DATA; | |
| 486 msg.arg1 = stream_; | |
| 487 msg.arg2 = read_size; | |
| 488 msg.arg3 = offset_; | |
| 489 msg.long_arg1 = remote_entry_; | |
| 490 SendMsg(msg); | |
| 491 } | |
| 492 | |
| 493 void MasterSM::DoReadData(int bytes_read) { | |
| 494 DEBUGMSG("Master DoReadData: %d bytes\n", input_->msg.buffer_bytes); | |
| 495 DCHECK(state_ == MASTER_READ_DATA); | |
| 496 DCHECK(input_->msg.command == READ_DATA); | |
| 497 if (input_->msg.result != RESULT_OK) | |
| 498 return Fail(); | |
| 499 | |
| 500 int read_size = input_->msg.buffer_bytes; | |
| 501 if (!read_size) { | |
| 502 printf("Read failed, entry \"%s\" truncated!\n", entry_->GetKey().c_str()); | |
| 503 bytes_remaining_ = 0; | |
| 504 return SendReadData(); | |
| 505 } | |
| 506 | |
| 507 scoped_refptr<net::WrappedIOBuffer> buf = | |
| 508 new net::WrappedIOBuffer(input_->buffer); | |
| 509 int rv = writer_->WriteEntry( | |
| 510 entry_, stream_, offset_, buf, read_size, | |
| 511 base::Bind(&MasterSM::DoReadDataComplete, base::Unretained(this))); | |
| 512 if (rv == net::ERR_IO_PENDING) { | |
| 513 // We'll continue in DoReadDataComplete. | |
| 514 read_size_ = read_size; | |
| 515 return; | |
| 516 } | |
| 517 | |
| 518 if (rv <= 0) | |
| 519 return Fail(); | |
| 520 | |
| 521 offset_ += read_size; | |
| 522 bytes_remaining_ -= read_size; | |
| 523 // Read some more. | |
| 524 SendReadData(); | |
| 525 } | |
| 526 | |
| 527 void MasterSM::DoReadDataComplete(int ret) { | |
| 528 if (ret != read_size_) | |
| 529 return Fail(); | |
| 530 | |
| 531 offset_ += ret; | |
| 532 bytes_remaining_ -= ret; | |
| 533 // Read some more. | |
| 534 SendReadData(); | |
| 535 } | |
| 536 | |
| 537 void MasterSM::SendQuit() { | |
| 538 DEBUGMSG("Master SendQuit\n"); | |
| 539 state_ = MASTER_END; | |
| 540 Message msg; | |
| 541 msg.command = QUIT; | |
| 542 SendMsg(msg); | |
| 543 if (!IsPending()) | |
| 544 DoEnd(); | |
| 545 } | |
| 546 | |
| 547 void MasterSM::DoEnd() { | |
| 548 DEBUGMSG("Master DoEnd\n"); | |
| 549 MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure()); | |
| 550 } | |
| 551 | |
| 552 void MasterSM::Fail() { | |
| 553 DEBUGMSG("Master Fail\n"); | |
| 554 printf("Unexpected failure\n"); | |
| 555 SendQuit(); | |
| 556 } | |
| 557 | |
| 558 // ----------------------------------------------------------------------- | |
| 559 | |
| 560 class SlaveSM : public BaseSM { | |
| 561 public: | |
| 562 SlaveSM(const FilePath& path, HANDLE channel); | |
| 563 virtual ~SlaveSM(); | |
| 564 | |
| 565 bool DoInit(); | |
| 566 virtual void OnIOCompleted(MessageLoopForIO::IOContext* context, | |
| 567 DWORD bytes_transfered, DWORD error); | |
| 568 | |
| 569 private: | |
| 570 enum { | |
| 571 SLAVE_INITIAL = 0, | |
| 572 SLAVE_WAITING, | |
| 573 SLAVE_END | |
| 574 }; | |
| 575 | |
| 576 void DoGetNextEntry(); | |
| 577 void DoGetPrevEntry(); | |
| 578 int32 GetEntryFromList(); | |
| 579 void DoGetEntryComplete(int result); | |
| 580 void DoCloseEntry(); | |
| 581 void DoGetKey(); | |
| 582 void DoGetUseTimes(); | |
| 583 void DoGetDataSize(); | |
| 584 void DoReadData(); | |
| 585 void DoReadDataComplete(int ret); | |
| 586 void DoEnd(); | |
| 587 void Fail(); | |
| 588 | |
| 589 void* iterator_; | |
| 590 Message msg_; // Used for DoReadDataComplete and DoGetEntryComplete. | |
| 591 | |
| 592 scoped_ptr<disk_cache::BackendImpl> cache_; | |
| 593 }; | |
| 594 | |
| 595 SlaveSM::SlaveSM(const FilePath& path, HANDLE channel) | |
| 596 : BaseSM(channel), iterator_(NULL) { | |
| 597 disk_cache::Backend* cache; | |
| 598 net::TestCompletionCallback cb; | |
| 599 int rv = disk_cache::CreateCacheBackend(net::DISK_CACHE, path, 0, false, | |
| 600 cache_thread_.message_loop_proxy(), | |
| 601 NULL, &cache, cb.callback()); | |
| 602 if (cb.GetResult(rv) != net::OK) { | |
| 603 printf("Unable to open cache files\n"); | |
| 604 return; | |
| 605 } | |
| 606 cache_.reset(reinterpret_cast<disk_cache::BackendImpl*>(cache)); | |
| 607 cache_->SetUpgradeMode(); | |
| 608 } | |
| 609 | |
| 610 SlaveSM::~SlaveSM() { | |
| 611 if (iterator_) | |
| 612 cache_->EndEnumeration(&iterator_); | |
| 613 } | |
| 614 | |
| 615 void SlaveSM::OnIOCompleted(MessageLoopForIO::IOContext* context, | |
| 616 DWORD bytes_transfered, DWORD error) { | |
| 617 pending_count_--; | |
| 618 if (state_ == SLAVE_END) { | |
| 619 if (IsPending()) | |
| 620 return; | |
| 621 return DoEnd(); | |
| 622 } | |
| 623 | |
| 624 if (context == &out_context_) { | |
| 625 if (!error) | |
| 626 return; | |
| 627 return Fail(); | |
| 628 } | |
| 629 | |
| 630 int bytes_read = static_cast<int>(bytes_transfered); | |
| 631 if (bytes_read < sizeof(Message)) { | |
| 632 printf("Communication breakdown\n"); | |
| 633 return Fail(); | |
| 634 } | |
| 635 DCHECK(state_ == SLAVE_WAITING); | |
| 636 | |
| 637 switch (input_->msg.command) { | |
| 638 case GET_NEXT_ENTRY: | |
| 639 DoGetNextEntry(); | |
| 640 break; | |
| 641 case GET_PREV_ENTRY: | |
| 642 DoGetPrevEntry(); | |
| 643 break; | |
| 644 case CLOSE_ENTRY: | |
| 645 DoCloseEntry(); | |
| 646 break; | |
| 647 case GET_KEY: | |
| 648 DoGetKey(); | |
| 649 break; | |
| 650 case GET_USE_TIMES: | |
| 651 DoGetUseTimes(); | |
| 652 break; | |
| 653 case GET_DATA_SIZE: | |
| 654 DoGetDataSize(); | |
| 655 break; | |
| 656 case READ_DATA: | |
| 657 DoReadData(); | |
| 658 break; | |
| 659 case QUIT: | |
| 660 DoEnd(); | |
| 661 break; | |
| 662 default: | |
| 663 NOTREACHED(); | |
| 664 break; | |
| 665 } | |
| 666 } | |
| 667 | |
| 668 bool SlaveSM::DoInit() { | |
| 669 DEBUGMSG("\t\t\tSlave DoInit\n"); | |
| 670 DCHECK(state_ == SLAVE_INITIAL); | |
| 671 state_ = SLAVE_WAITING; | |
| 672 if (!cache_.get()) | |
| 673 return false; | |
| 674 | |
| 675 return ReceiveMsg(); | |
| 676 } | |
| 677 | |
| 678 void SlaveSM::DoGetNextEntry() { | |
| 679 DEBUGMSG("\t\t\tSlave DoGetNextEntry\n"); | |
| 680 Message msg; | |
| 681 msg.command = GET_NEXT_ENTRY; | |
| 682 | |
| 683 if (input_->msg.arg1) { | |
| 684 // We only support one list. | |
| 685 msg.result = RESULT_UNKNOWN_COMMAND; | |
| 686 } else { | |
| 687 msg.result = GetEntryFromList(); | |
| 688 msg.long_arg1 = reinterpret_cast<int64>(entry_); | |
| 689 } | |
| 690 SendMsg(msg); | |
| 691 } | |
| 692 | |
| 693 void SlaveSM::DoGetPrevEntry() { | |
| 694 DEBUGMSG("\t\t\tSlave DoGetPrevEntry\n"); | |
| 695 Message msg; | |
| 696 msg.command = GET_PREV_ENTRY; | |
| 697 | |
| 698 if (input_->msg.arg1) { | |
| 699 // We only support one list. | |
| 700 msg.result = RESULT_UNKNOWN_COMMAND; | |
| 701 } else { | |
| 702 msg.result = GetEntryFromList(); | |
| 703 if (msg.result == RESULT_PENDING) { | |
| 704 // We are not done yet. | |
| 705 msg_ = msg; | |
| 706 return; | |
| 707 } | |
| 708 msg.long_arg1 = reinterpret_cast<int64>(entry_); | |
| 709 } | |
| 710 SendMsg(msg); | |
| 711 } | |
| 712 | |
| 713 // Move to the next or previous entry on the list. | |
| 714 int32 SlaveSM::GetEntryFromList() { | |
| 715 DEBUGMSG("\t\t\tSlave GetEntryFromList\n"); | |
| 716 if (input_->msg.long_arg1 != reinterpret_cast<int64>(entry_)) | |
| 717 return RESULT_INVALID_PARAMETER; | |
| 718 | |
| 719 // We know that the current iteration is valid. | |
| 720 if (entry_) | |
| 721 entry_->Close(); | |
| 722 | |
| 723 int rv; | |
| 724 if (input_->msg.command == GET_NEXT_ENTRY) { | |
| 725 rv = cache_->OpenNextEntry( | |
| 726 &iterator_, reinterpret_cast<disk_cache::Entry**>(&entry_), | |
| 727 base::Bind(&SlaveSM::DoGetEntryComplete, base::Unretained(this))); | |
| 728 } else { | |
| 729 DCHECK(input_->msg.command == GET_PREV_ENTRY); | |
| 730 rv = cache_->OpenPrevEntry(&iterator_, | |
| 731 reinterpret_cast<disk_cache::Entry**>(&entry_), | |
| 732 base::Bind(&SlaveSM::DoGetEntryComplete, | |
| 733 base::Unretained(this))); | |
| 734 } | |
| 735 DCHECK_EQ(net::ERR_IO_PENDING, rv); | |
| 736 return RESULT_PENDING; | |
| 737 } | |
| 738 | |
| 739 void SlaveSM::DoGetEntryComplete(int result) { | |
| 740 DEBUGMSG("\t\t\tSlave DoGetEntryComplete\n"); | |
| 741 if (result != net::OK) { | |
| 742 entry_ = NULL; | |
| 743 DEBUGMSG("\t\t\tSlave end of list\n"); | |
| 744 } | |
| 745 | |
| 746 msg_.result = RESULT_OK; | |
| 747 msg_.long_arg1 = reinterpret_cast<int64>(entry_); | |
| 748 SendMsg(msg_); | |
| 749 } | |
| 750 | |
| 751 void SlaveSM::DoCloseEntry() { | |
| 752 DEBUGMSG("\t\t\tSlave DoCloseEntry\n"); | |
| 753 Message msg; | |
| 754 msg.command = GET_KEY; | |
| 755 | |
| 756 if (!entry_ || input_->msg.long_arg1 != reinterpret_cast<int64>(entry_)) { | |
| 757 msg.result = RESULT_INVALID_PARAMETER; | |
| 758 } else { | |
| 759 entry_->Close(); | |
| 760 entry_ = NULL; | |
| 761 cache_->EndEnumeration(&iterator_); | |
| 762 msg.result = RESULT_OK; | |
| 763 } | |
| 764 SendMsg(msg); | |
| 765 } | |
| 766 | |
| 767 void SlaveSM::DoGetKey() { | |
| 768 DEBUGMSG("\t\t\tSlave DoGetKey\n"); | |
| 769 Message msg; | |
| 770 msg.command = GET_KEY; | |
| 771 | |
| 772 if (!entry_ || input_->msg.long_arg1 != reinterpret_cast<int64>(entry_)) { | |
| 773 msg.result = RESULT_INVALID_PARAMETER; | |
| 774 } else { | |
| 775 std::string key = entry_->GetKey(); | |
| 776 msg.buffer_bytes = std::min(key.size() + 1, | |
| 777 static_cast<size_t>(kBufferSize)); | |
| 778 memcpy(output_->buffer, key.c_str(), msg.buffer_bytes); | |
| 779 if (msg.buffer_bytes != static_cast<int32>(key.size() + 1)) { | |
| 780 // We don't support moving this entry. Just tell the master. | |
| 781 msg.result = RESULT_NAME_OVERFLOW; | |
| 782 } else { | |
| 783 msg.result = RESULT_OK; | |
| 784 } | |
| 785 } | |
| 786 SendMsg(msg); | |
| 787 } | |
| 788 | |
| 789 void SlaveSM::DoGetUseTimes() { | |
| 790 DEBUGMSG("\t\t\tSlave DoGetUseTimes\n"); | |
| 791 Message msg; | |
| 792 msg.command = GET_USE_TIMES; | |
| 793 | |
| 794 if (!entry_ || input_->msg.long_arg1 != reinterpret_cast<int64>(entry_)) { | |
| 795 msg.result = RESULT_INVALID_PARAMETER; | |
| 796 } else { | |
| 797 msg.long_arg2 = entry_->GetLastUsed().ToInternalValue(); | |
| 798 msg.long_arg3 = entry_->GetLastModified().ToInternalValue(); | |
| 799 msg.result = RESULT_OK; | |
| 800 } | |
| 801 SendMsg(msg); | |
| 802 } | |
| 803 | |
| 804 void SlaveSM::DoGetDataSize() { | |
| 805 DEBUGMSG("\t\t\tSlave DoGetDataSize\n"); | |
| 806 Message msg; | |
| 807 msg.command = GET_DATA_SIZE; | |
| 808 | |
| 809 int stream = input_->msg.arg1; | |
| 810 if (!entry_ || input_->msg.long_arg1 != reinterpret_cast<int64>(entry_) || | |
| 811 stream < 0 || stream >= kNumStreams) { | |
| 812 msg.result = RESULT_INVALID_PARAMETER; | |
| 813 } else { | |
| 814 msg.arg1 = stream; | |
| 815 msg.arg2 = entry_->GetDataSize(stream); | |
| 816 msg.result = RESULT_OK; | |
| 817 } | |
| 818 SendMsg(msg); | |
| 819 } | |
| 820 | |
| 821 void SlaveSM::DoReadData() { | |
| 822 DEBUGMSG("\t\t\tSlave DoReadData\n"); | |
| 823 Message msg; | |
| 824 msg.command = READ_DATA; | |
| 825 | |
| 826 int stream = input_->msg.arg1; | |
| 827 int size = input_->msg.arg2; | |
| 828 if (!entry_ || input_->msg.long_arg1 != reinterpret_cast<int64>(entry_) || | |
| 829 stream < 0 || stream > 1 || size > kBufferSize) { | |
| 830 msg.result = RESULT_INVALID_PARAMETER; | |
| 831 } else { | |
| 832 scoped_refptr<net::WrappedIOBuffer> buf = | |
| 833 new net::WrappedIOBuffer(output_->buffer); | |
| 834 int ret = entry_->ReadData(stream, input_->msg.arg3, buf, size, | |
| 835 base::Bind(&SlaveSM::DoReadDataComplete, | |
| 836 base::Unretained(this))); | |
| 837 if (ret == net::ERR_IO_PENDING) { | |
| 838 // Save the message so we can continue were we left. | |
| 839 msg_ = msg; | |
| 840 return; | |
| 841 } | |
| 842 | |
| 843 msg.buffer_bytes = (ret < 0) ? 0 : ret; | |
| 844 msg.result = RESULT_OK; | |
| 845 } | |
| 846 SendMsg(msg); | |
| 847 } | |
| 848 | |
| 849 void SlaveSM::DoReadDataComplete(int ret) { | |
| 850 DEBUGMSG("\t\t\tSlave DoReadDataComplete\n"); | |
| 851 DCHECK_EQ(READ_DATA, msg_.command); | |
| 852 msg_.buffer_bytes = (ret < 0) ? 0 : ret; | |
| 853 msg_.result = RESULT_OK; | |
| 854 SendMsg(msg_); | |
| 855 } | |
| 856 | |
| 857 void SlaveSM::DoEnd() { | |
| 858 DEBUGMSG("\t\t\tSlave DoEnd\n"); | |
| 859 MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure()); | |
| 860 } | |
| 861 | |
| 862 void SlaveSM::Fail() { | |
| 863 DEBUGMSG("\t\t\tSlave Fail\n"); | |
| 864 printf("Unexpected failure\n"); | |
| 865 state_ = SLAVE_END; | |
| 866 if (IsPending()) { | |
| 867 CancelIo(channel_); | |
| 868 } else { | |
| 869 DoEnd(); | |
| 870 } | |
| 871 } | |
| 872 | |
| 873 } // namespace. | |
| 874 | |
| 875 // ----------------------------------------------------------------------- | |
| 876 | |
| 877 HANDLE CreateServer(std::wstring* pipe_number) { | |
| 878 std::wstring pipe_name(kPipePrefix); | |
| 879 srand(static_cast<int>(base::Time::Now().ToInternalValue())); | |
| 880 *pipe_number = base::IntToString16(rand()); | |
| 881 pipe_name.append(*pipe_number); | |
| 882 | |
| 883 DWORD mode = PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | | |
| 884 FILE_FLAG_OVERLAPPED; | |
| 885 | |
| 886 return CreateNamedPipe(pipe_name.c_str(), mode, 0, 1, kChannelSize, | |
| 887 kChannelSize, 0, NULL); | |
| 888 } | |
| 889 | |
| 890 // This is the controller process for an upgrade operation. | |
| 891 int CopyCache(const FilePath& output_path, HANDLE pipe, bool copy_to_text) { | |
| 892 MessageLoop loop(MessageLoop::TYPE_IO); | |
| 893 | |
| 894 MasterSM master(output_path, pipe, copy_to_text); | |
| 895 if (!master.DoInit()) { | |
| 896 printf("Unable to talk with the helper\n"); | |
| 897 return -1; | |
| 898 } | |
| 899 | |
| 900 loop.Run(); | |
| 901 return 0; | |
| 902 } | |
| 903 | |
| 904 // This process will only execute commands from the controller. | |
| 905 int RunSlave(const FilePath& input_path, const std::wstring& pipe_number) { | |
| 906 MessageLoop loop(MessageLoop::TYPE_IO); | |
| 907 | |
| 908 base::win::ScopedHandle pipe(OpenServer(pipe_number)); | |
| 909 if (!pipe.IsValid()) { | |
| 910 printf("Unable to open the server pipe\n"); | |
| 911 return -1; | |
| 912 } | |
| 913 | |
| 914 SlaveSM slave(input_path, pipe); | |
| 915 if (!slave.DoInit()) { | |
| 916 printf("Unable to talk with the main process\n"); | |
| 917 return -1; | |
| 918 } | |
| 919 | |
| 920 loop.Run(); | |
| 921 return 0; | |
| 922 } | |
| OLD | NEW |