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