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