1 // Copyright 2016 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 "mojo/edk/system/channel.h" 6 7 #include <stddef.h> 8 #include <string.h> 9 10 #include <algorithm> 11 #include <limits> 12 #include <utility> 13 14 #include "base/macros.h" 15 #include "base/memory/aligned_memory.h" 16 #include "base/process/process_handle.h" 17 #include "mojo/edk/embedder/platform_handle.h" 18 19 #if defined(OS_MACOSX) && !defined(OS_IOS) 20 #include "base/mac/mach_logging.h" 21 #elif defined(OS_WIN) 22 #include "base/win/win_util.h" 23 #endif 24 25 namespace mojo { 26 namespace edk { 27 28 namespace { 29 30 static_assert( 31 IsAlignedForChannelMessage(sizeof(Channel::Message::LegacyHeader)), 32 "Invalid LegacyHeader size."); 33 34 static_assert(IsAlignedForChannelMessage(sizeof(Channel::Message::Header)), 35 "Invalid Header size."); 36 37 static_assert(sizeof(Channel::Message::LegacyHeader) == 8, 38 "LegacyHeader must be 8 bytes on ChromeOS and Android"); 39 40 static_assert(offsetof(Channel::Message::LegacyHeader, num_bytes) == 41 offsetof(Channel::Message::Header, num_bytes), 42 "num_bytes should be at the same offset in both Header structs."); 43 static_assert(offsetof(Channel::Message::LegacyHeader, message_type) == 44 offsetof(Channel::Message::Header, message_type), 45 "message_type should be at the same offset in both Header " 46 "structs."); 47 48 } // namespace 49 50 const size_t kReadBufferSize = 4096; 51 const size_t kMaxUnusedReadBufferCapacity = 4096; 52 const size_t kMaxChannelMessageSize = 256 * 1024 * 1024; 53 const size_t kMaxAttachedHandles = 128; 54 55 Channel::Message::Message(size_t payload_size, size_t max_handles) 56 #if defined(MOJO_EDK_LEGACY_PROTOCOL) 57 : Message(payload_size, max_handles, MessageType::NORMAL_LEGACY) { 58 } 59 #else 60 : Message(payload_size, max_handles, MessageType::NORMAL) { 61 } 62 #endif 63 64 Channel::Message::Message(size_t payload_size, 65 size_t max_handles, 66 MessageType message_type) 67 : max_handles_(max_handles) { 68 DCHECK_LE(max_handles_, kMaxAttachedHandles); 69 70 const bool is_legacy_message = (message_type == MessageType::NORMAL_LEGACY); 71 size_t extra_header_size = 0; 72 #if defined(OS_WIN) 73 // On Windows we serialize HANDLEs into the extra header space. 74 extra_header_size = max_handles_ * sizeof(HandleEntry); 75 #elif defined(OS_MACOSX) && !defined(OS_IOS) 76 // On OSX, some of the platform handles may be mach ports, which are 77 // serialised into the message buffer. Since there could be a mix of fds and 78 // mach ports, we store the mach ports as an <index, port> pair (of uint32_t), 79 // so that the original ordering of handles can be re-created. 80 if (max_handles) { 81 extra_header_size = 82 sizeof(MachPortsExtraHeader) + (max_handles * sizeof(MachPortsEntry)); 83 } 84 #endif 85 // Pad extra header data to be aliged to |kChannelMessageAlignment| bytes. 86 if (!IsAlignedForChannelMessage(extra_header_size)) { 87 extra_header_size += kChannelMessageAlignment - 88 (extra_header_size % kChannelMessageAlignment); 89 } 90 DCHECK(IsAlignedForChannelMessage(extra_header_size)); 91 const size_t header_size = 92 is_legacy_message ? sizeof(LegacyHeader) : sizeof(Header); 93 DCHECK(extra_header_size == 0 || !is_legacy_message); 94 95 size_ = header_size + extra_header_size + payload_size; 96 data_ = static_cast<char*>(base::AlignedAlloc(size_, 97 kChannelMessageAlignment)); 98 // Only zero out the header and not the payload. Since the payload is going to 99 // be memcpy'd, zeroing the payload is unnecessary work and a significant 100 // performance issue when dealing with large messages. Any sanitizer errors 101 // complaining about an uninitialized read in the payload area should be 102 // treated as an error and fixed. 103 memset(data_, 0, header_size + extra_header_size); 104 105 DCHECK_LE(size_, std::numeric_limits<uint32_t>::max()); 106 legacy_header()->num_bytes = static_cast<uint32_t>(size_); 107 108 DCHECK_LE(header_size + extra_header_size, 109 std::numeric_limits<uint16_t>::max()); 110 legacy_header()->message_type = message_type; 111 112 if (is_legacy_message) { 113 legacy_header()->num_handles = static_cast<uint16_t>(max_handles); 114 } else { 115 header()->num_header_bytes = 116 static_cast<uint16_t>(header_size + extra_header_size); 117 } 118 119 if (max_handles_ > 0) { 120 #if defined(OS_WIN) 121 handles_ = reinterpret_cast<HandleEntry*>(mutable_extra_header()); 122 // Initialize all handles to invalid values. 123 for (size_t i = 0; i < max_handles_; ++i) 124 handles_[i].handle = base::win::HandleToUint32(INVALID_HANDLE_VALUE); 125 #elif defined(OS_MACOSX) && !defined(OS_IOS) 126 mach_ports_header_ = 127 reinterpret_cast<MachPortsExtraHeader*>(mutable_extra_header()); 128 mach_ports_header_->num_ports = 0; 129 // Initialize all handles to invalid values. 130 for (size_t i = 0; i < max_handles_; ++i) { 131 mach_ports_header_->entries[i] = 132 {0, static_cast<uint32_t>(MACH_PORT_NULL)}; 133 } 134 #endif 135 } 136 } 137 138 Channel::Message::~Message() { 139 base::AlignedFree(data_); 140 } 141 142 // static 143 Channel::MessagePtr Channel::Message::Deserialize(const void* data, 144 size_t data_num_bytes) { 145 if (data_num_bytes < sizeof(LegacyHeader)) 146 return nullptr; 147 148 const LegacyHeader* legacy_header = 149 reinterpret_cast<const LegacyHeader*>(data); 150 if (legacy_header->num_bytes != data_num_bytes) { 151 DLOG(ERROR) << "Decoding invalid message: " << legacy_header->num_bytes 152 << " != " << data_num_bytes; 153 return nullptr; 154 } 155 156 const Header* header = nullptr; 157 if (legacy_header->message_type == MessageType::NORMAL) 158 header = reinterpret_cast<const Header*>(data); 159 160 uint32_t extra_header_size = 0; 161 size_t payload_size = 0; 162 const char* payload = nullptr; 163 if (!header) { 164 payload_size = data_num_bytes - sizeof(LegacyHeader); 165 payload = static_cast<const char*>(data) + sizeof(LegacyHeader); 166 } else { 167 if (header->num_bytes < header->num_header_bytes || 168 header->num_header_bytes < sizeof(Header)) { 169 DLOG(ERROR) << "Decoding invalid message: " << header->num_bytes << " < " 170 << header->num_header_bytes; 171 return nullptr; 172 } 173 extra_header_size = header->num_header_bytes - sizeof(Header); 174 payload_size = data_num_bytes - header->num_header_bytes; 175 payload = static_cast<const char*>(data) + header->num_header_bytes; 176 } 177 178 #if defined(OS_WIN) 179 uint32_t max_handles = extra_header_size / sizeof(HandleEntry); 180 #elif defined(OS_MACOSX) && !defined(OS_IOS) 181 if (extra_header_size > 0 && 182 extra_header_size < sizeof(MachPortsExtraHeader)) { 183 DLOG(ERROR) << "Decoding invalid message: " << extra_header_size << " < " 184 << sizeof(MachPortsExtraHeader); 185 return nullptr; 186 } 187 uint32_t max_handles = 188 extra_header_size == 0 189 ? 0 190 : (extra_header_size - sizeof(MachPortsExtraHeader)) / 191 sizeof(MachPortsEntry); 192 #else 193 const uint32_t max_handles = 0; 194 #endif // defined(OS_WIN) 195 196 const uint16_t num_handles = 197 header ? header->num_handles : legacy_header->num_handles; 198 if (num_handles > max_handles || max_handles > kMaxAttachedHandles) { 199 DLOG(ERROR) << "Decoding invalid message: " << num_handles << " > " 200 << max_handles; 201 return nullptr; 202 } 203 204 MessagePtr message( 205 new Message(payload_size, max_handles, legacy_header->message_type)); 206 DCHECK_EQ(message->data_num_bytes(), data_num_bytes); 207 208 // Copy all payload bytes. 209 if (payload_size) 210 memcpy(message->mutable_payload(), payload, payload_size); 211 212 if (header) { 213 DCHECK_EQ(message->extra_header_size(), extra_header_size); 214 DCHECK_EQ(message->header()->num_header_bytes, header->num_header_bytes); 215 216 if (message->extra_header_size()) { 217 // Copy extra header bytes. 218 memcpy(message->mutable_extra_header(), 219 static_cast<const char*>(data) + sizeof(Header), 220 message->extra_header_size()); 221 } 222 message->header()->num_handles = header->num_handles; 223 } else { 224 message->legacy_header()->num_handles = legacy_header->num_handles; 225 } 226 227 #if defined(OS_WIN) 228 ScopedPlatformHandleVectorPtr handles(new PlatformHandleVector(num_handles)); 229 for (size_t i = 0; i < num_handles; i++) { 230 (*handles)[i].handle = 231 base::win::Uint32ToHandle(message->handles_[i].handle); 232 } 233 message->SetHandles(std::move(handles)); 234 #endif 235 236 return message; 237 } 238 239 const void* Channel::Message::extra_header() const { 240 DCHECK(!is_legacy_message()); 241 return data_ + sizeof(Header); 242 } 243 244 void* Channel::Message::mutable_extra_header() { 245 DCHECK(!is_legacy_message()); 246 return data_ + sizeof(Header); 247 } 248 249 size_t Channel::Message::extra_header_size() const { 250 return header()->num_header_bytes - sizeof(Header); 251 } 252 253 void* Channel::Message::mutable_payload() { 254 if (is_legacy_message()) 255 return static_cast<void*>(legacy_header() + 1); 256 return data_ + header()->num_header_bytes; 257 } 258 259 const void* Channel::Message::payload() const { 260 if (is_legacy_message()) 261 return static_cast<const void*>(legacy_header() + 1); 262 return data_ + header()->num_header_bytes; 263 } 264 265 size_t Channel::Message::payload_size() const { 266 if (is_legacy_message()) 267 return legacy_header()->num_bytes - sizeof(LegacyHeader); 268 return size_ - header()->num_header_bytes; 269 } 270 271 size_t Channel::Message::num_handles() const { 272 return is_legacy_message() ? legacy_header()->num_handles 273 : header()->num_handles; 274 } 275 276 bool Channel::Message::has_handles() const { 277 return (is_legacy_message() ? legacy_header()->num_handles 278 : header()->num_handles) > 0; 279 } 280 281 #if defined(OS_MACOSX) && !defined(OS_IOS) 282 bool Channel::Message::has_mach_ports() const { 283 if (!has_handles()) 284 return false; 285 286 for (const auto& handle : (*handle_vector_)) { 287 if (handle.type == PlatformHandle::Type::MACH || 288 handle.type == PlatformHandle::Type::MACH_NAME) { 289 return true; 290 } 291 } 292 return false; 293 } 294 #endif 295 296 bool Channel::Message::is_legacy_message() const { 297 return legacy_header()->message_type == MessageType::NORMAL_LEGACY; 298 } 299 300 Channel::Message::LegacyHeader* Channel::Message::legacy_header() const { 301 return reinterpret_cast<LegacyHeader*>(data_); 302 } 303 304 Channel::Message::Header* Channel::Message::header() const { 305 DCHECK(!is_legacy_message()); 306 return reinterpret_cast<Header*>(data_); 307 } 308 309 void Channel::Message::SetHandles(ScopedPlatformHandleVectorPtr new_handles) { 310 if (is_legacy_message()) { 311 // Old semantics for ChromeOS and Android 312 if (legacy_header()->num_handles == 0) { 313 CHECK(!new_handles || new_handles->size() == 0); 314 return; 315 } 316 CHECK(new_handles && new_handles->size() == legacy_header()->num_handles); 317 std::swap(handle_vector_, new_handles); 318 return; 319 } 320 321 if (max_handles_ == 0) { 322 CHECK(!new_handles || new_handles->size() == 0); 323 return; 324 } 325 326 CHECK(new_handles && new_handles->size() <= max_handles_); 327 header()->num_handles = static_cast<uint16_t>(new_handles->size()); 328 std::swap(handle_vector_, new_handles); 329 #if defined(OS_WIN) 330 memset(handles_, 0, extra_header_size()); 331 for (size_t i = 0; i < handle_vector_->size(); i++) 332 handles_[i].handle = base::win::HandleToUint32((*handle_vector_)[i].handle); 333 #endif // defined(OS_WIN) 334 335 #if defined(OS_MACOSX) && !defined(OS_IOS) 336 size_t mach_port_index = 0; 337 if (mach_ports_header_) { 338 for (size_t i = 0; i < max_handles_; ++i) { 339 mach_ports_header_->entries[i] = 340 {0, static_cast<uint32_t>(MACH_PORT_NULL)}; 341 } 342 for (size_t i = 0; i < handle_vector_->size(); i++) { 343 if ((*handle_vector_)[i].type == PlatformHandle::Type::MACH || 344 (*handle_vector_)[i].type == PlatformHandle::Type::MACH_NAME) { 345 mach_port_t port = (*handle_vector_)[i].port; 346 mach_ports_header_->entries[mach_port_index].index = i; 347 mach_ports_header_->entries[mach_port_index].mach_port = port; 348 mach_port_index++; 349 } 350 } 351 mach_ports_header_->num_ports = static_cast<uint16_t>(mach_port_index); 352 } 353 #endif 354 } 355 356 ScopedPlatformHandleVectorPtr Channel::Message::TakeHandles() { 357 #if defined(OS_MACOSX) && !defined(OS_IOS) 358 if (mach_ports_header_) { 359 for (size_t i = 0; i < max_handles_; ++i) { 360 mach_ports_header_->entries[i] = 361 {0, static_cast<uint32_t>(MACH_PORT_NULL)}; 362 } 363 mach_ports_header_->num_ports = 0; 364 } 365 #endif 366 if (is_legacy_message()) 367 legacy_header()->num_handles = 0; 368 else 369 header()->num_handles = 0; 370 return std::move(handle_vector_); 371 } 372 373 ScopedPlatformHandleVectorPtr Channel::Message::TakeHandlesForTransport() { 374 #if defined(OS_WIN) 375 // Not necessary on Windows. 376 NOTREACHED(); 377 return nullptr; 378 #elif defined(OS_MACOSX) && !defined(OS_IOS) 379 if (handle_vector_) { 380 for (auto it = handle_vector_->begin(); it != handle_vector_->end(); ) { 381 if (it->type == PlatformHandle::Type::MACH || 382 it->type == PlatformHandle::Type::MACH_NAME) { 383 // For Mach port names, we can can just leak them. They're not real 384 // ports anyways. For real ports, they're leaked because this is a child 385 // process and the remote process will take ownership. 386 it = handle_vector_->erase(it); 387 } else { 388 ++it; 389 } 390 } 391 } 392 return std::move(handle_vector_); 393 #else 394 return std::move(handle_vector_); 395 #endif 396 } 397 398 #if defined(OS_WIN) 399 // static 400 bool Channel::Message::RewriteHandles(base::ProcessHandle from_process, 401 base::ProcessHandle to_process, 402 PlatformHandleVector* handles) { 403 bool success = true; 404 for (size_t i = 0; i < handles->size(); ++i) { 405 if (!(*handles)[i].is_valid()) { 406 DLOG(ERROR) << "Refusing to duplicate invalid handle."; 407 continue; 408 } 409 DCHECK_EQ((*handles)[i].owning_process, from_process); 410 BOOL result = DuplicateHandle( 411 from_process, (*handles)[i].handle, to_process, 412 &(*handles)[i].handle, 0, FALSE, 413 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); 414 if (result) { 415 (*handles)[i].owning_process = to_process; 416 } else { 417 success = false; 418 419 // If handle duplication fails, the source handle will already be closed 420 // due to DUPLICATE_CLOSE_SOURCE. Replace the handle in the message with 421 // an invalid handle. 422 (*handles)[i].handle = INVALID_HANDLE_VALUE; 423 (*handles)[i].owning_process = base::GetCurrentProcessHandle(); 424 } 425 } 426 return success; 427 } 428 #endif 429 430 // Helper class for managing a Channel's read buffer allocations. This maintains 431 // a single contiguous buffer with the layout: 432 // 433 // [discarded bytes][occupied bytes][unoccupied bytes] 434 // 435 // The Reserve() method ensures that a certain capacity of unoccupied bytes are 436 // available. It does not claim that capacity and only allocates new capacity 437 // when strictly necessary. 438 // 439 // Claim() marks unoccupied bytes as occupied. 440 // 441 // Discard() marks occupied bytes as discarded, signifying that their contents 442 // can be forgotten or overwritten. 443 // 444 // Realign() moves occupied bytes to the front of the buffer so that those 445 // occupied bytes are properly aligned. 446 // 447 // The most common Channel behavior in practice should result in very few 448 // allocations and copies, as memory is claimed and discarded shortly after 449 // being reserved, and future reservations will immediately reuse discarded 450 // memory. 451 class Channel::ReadBuffer { 452 public: 453 ReadBuffer() { 454 size_ = kReadBufferSize; 455 data_ = static_cast<char*>(base::AlignedAlloc(size_, 456 kChannelMessageAlignment)); 457 } 458 459 ~ReadBuffer() { 460 DCHECK(data_); 461 base::AlignedFree(data_); 462 } 463 464 const char* occupied_bytes() const { return data_ + num_discarded_bytes_; } 465 466 size_t num_occupied_bytes() const { 467 return num_occupied_bytes_ - num_discarded_bytes_; 468 } 469 470 // Ensures the ReadBuffer has enough contiguous space allocated to hold 471 // |num_bytes| more bytes; returns the address of the first available byte. 472 char* Reserve(size_t num_bytes) { 473 if (num_occupied_bytes_ + num_bytes > size_) { 474 size_ = std::max(size_ * 2, num_occupied_bytes_ + num_bytes); 475 void* new_data = base::AlignedAlloc(size_, kChannelMessageAlignment); 476 memcpy(new_data, data_, num_occupied_bytes_); 477 base::AlignedFree(data_); 478 data_ = static_cast<char*>(new_data); 479 } 480 481 return data_ + num_occupied_bytes_; 482 } 483 484 // Marks the first |num_bytes| unoccupied bytes as occupied. 485 void Claim(size_t num_bytes) { 486 DCHECK_LE(num_occupied_bytes_ + num_bytes, size_); 487 num_occupied_bytes_ += num_bytes; 488 } 489 490 // Marks the first |num_bytes| occupied bytes as discarded. This may result in 491 // shrinkage of the internal buffer, and it is not safe to assume the result 492 // of a previous Reserve() call is still valid after this. 493 void Discard(size_t num_bytes) { 494 DCHECK_LE(num_discarded_bytes_ + num_bytes, num_occupied_bytes_); 495 num_discarded_bytes_ += num_bytes; 496 497 if (num_discarded_bytes_ == num_occupied_bytes_) { 498 // We can just reuse the buffer from the beginning in this common case. 499 num_discarded_bytes_ = 0; 500 num_occupied_bytes_ = 0; 501 } 502 503 if (num_discarded_bytes_ > kMaxUnusedReadBufferCapacity) { 504 // In the uncommon case that we have a lot of discarded data at the 505 // front of the buffer, simply move remaining data to a smaller buffer. 506 size_t num_preserved_bytes = num_occupied_bytes_ - num_discarded_bytes_; 507 size_ = std::max(num_preserved_bytes, kReadBufferSize); 508 char* new_data = static_cast<char*>( 509 base::AlignedAlloc(size_, kChannelMessageAlignment)); 510 memcpy(new_data, data_ + num_discarded_bytes_, num_preserved_bytes); 511 base::AlignedFree(data_); 512 data_ = new_data; 513 num_discarded_bytes_ = 0; 514 num_occupied_bytes_ = num_preserved_bytes; 515 } 516 517 if (num_occupied_bytes_ == 0 && size_ > kMaxUnusedReadBufferCapacity) { 518 // Opportunistically shrink the read buffer back down to a small size if 519 // it's grown very large. We only do this if there are no remaining 520 // unconsumed bytes in the buffer to avoid copies in most the common 521 // cases. 522 size_ = kMaxUnusedReadBufferCapacity; 523 base::AlignedFree(data_); 524 data_ = static_cast<char*>( 525 base::AlignedAlloc(size_, kChannelMessageAlignment)); 526 } 527 } 528 529 void Realign() { 530 size_t num_bytes = num_occupied_bytes(); 531 memmove(data_, occupied_bytes(), num_bytes); 532 num_discarded_bytes_ = 0; 533 num_occupied_bytes_ = num_bytes; 534 } 535 536 private: 537 char* data_ = nullptr; 538 539 // The total size of the allocated buffer. 540 size_t size_ = 0; 541 542 // The number of discarded bytes at the beginning of the allocated buffer. 543 size_t num_discarded_bytes_ = 0; 544 545 // The total number of occupied bytes, including discarded bytes. 546 size_t num_occupied_bytes_ = 0; 547 548 DISALLOW_COPY_AND_ASSIGN(ReadBuffer); 549 }; 550 551 Channel::Channel(Delegate* delegate) 552 : delegate_(delegate), read_buffer_(new ReadBuffer) { 553 } 554 555 Channel::~Channel() { 556 } 557 558 void Channel::ShutDown() { 559 delegate_ = nullptr; 560 ShutDownImpl(); 561 } 562 563 char* Channel::GetReadBuffer(size_t *buffer_capacity) { 564 DCHECK(read_buffer_); 565 size_t required_capacity = *buffer_capacity; 566 if (!required_capacity) 567 required_capacity = kReadBufferSize; 568 569 *buffer_capacity = required_capacity; 570 return read_buffer_->Reserve(required_capacity); 571 } 572 573 bool Channel::OnReadComplete(size_t bytes_read, size_t *next_read_size_hint) { 574 bool did_dispatch_message = false; 575 read_buffer_->Claim(bytes_read); 576 while (read_buffer_->num_occupied_bytes() >= sizeof(Message::LegacyHeader)) { 577 // Ensure the occupied data is properly aligned. If it isn't, a SIGBUS could 578 // happen on architectures that don't allow misaligned words access (i.e. 579 // anything other than x86). Only re-align when necessary to avoid copies. 580 if (!IsAlignedForChannelMessage( 581 reinterpret_cast<uintptr_t>(read_buffer_->occupied_bytes()))) { 582 read_buffer_->Realign(); 583 } 584 585 // We have at least enough data available for a LegacyHeader. 586 const Message::LegacyHeader* legacy_header = 587 reinterpret_cast<const Message::LegacyHeader*>( 588 read_buffer_->occupied_bytes()); 589 590 if (legacy_header->num_bytes < sizeof(Message::LegacyHeader) || 591 legacy_header->num_bytes > kMaxChannelMessageSize) { 592 LOG(ERROR) << "Invalid message size: " << legacy_header->num_bytes; 593 return false; 594 } 595 596 if (read_buffer_->num_occupied_bytes() < legacy_header->num_bytes) { 597 // Not enough data available to read the full message. Hint to the 598 // implementation that it should try reading the full size of the message. 599 *next_read_size_hint = 600 legacy_header->num_bytes - read_buffer_->num_occupied_bytes(); 601 return true; 602 } 603 604 const Message::Header* header = nullptr; 605 if (legacy_header->message_type != Message::MessageType::NORMAL_LEGACY) { 606 header = reinterpret_cast<const Message::Header*>(legacy_header); 607 } 608 609 size_t extra_header_size = 0; 610 const void* extra_header = nullptr; 611 size_t payload_size = 0; 612 void* payload = nullptr; 613 if (header) { 614 if (header->num_header_bytes < sizeof(Message::Header) || 615 header->num_header_bytes > header->num_bytes) { 616 LOG(ERROR) << "Invalid message header size: " 617 << header->num_header_bytes; 618 return false; 619 } 620 extra_header_size = header->num_header_bytes - sizeof(Message::Header); 621 extra_header = extra_header_size ? header + 1 : nullptr; 622 payload_size = header->num_bytes - header->num_header_bytes; 623 payload = payload_size 624 ? reinterpret_cast<Message::Header*>( 625 const_cast<char*>(read_buffer_->occupied_bytes()) + 626 header->num_header_bytes) 627 : nullptr; 628 } else { 629 payload_size = legacy_header->num_bytes - sizeof(Message::LegacyHeader); 630 payload = payload_size 631 ? const_cast<Message::LegacyHeader*>(&legacy_header[1]) 632 : nullptr; 633 } 634 635 const uint16_t num_handles = 636 header ? header->num_handles : legacy_header->num_handles; 637 ScopedPlatformHandleVectorPtr handles; 638 if (num_handles > 0) { 639 if (!GetReadPlatformHandles(num_handles, extra_header, extra_header_size, 640 &handles)) { 641 return false; 642 } 643 644 if (!handles) { 645 // Not enough handles available for this message. 646 break; 647 } 648 } 649 650 // We've got a complete message! Dispatch it and try another. 651 if (legacy_header->message_type != Message::MessageType::NORMAL_LEGACY && 652 legacy_header->message_type != Message::MessageType::NORMAL) { 653 if (!OnControlMessage(legacy_header->message_type, payload, payload_size, 654 std::move(handles))) { 655 return false; 656 } 657 did_dispatch_message = true; 658 } else if (delegate_) { 659 delegate_->OnChannelMessage(payload, payload_size, std::move(handles)); 660 did_dispatch_message = true; 661 } 662 663 read_buffer_->Discard(legacy_header->num_bytes); 664 } 665 666 *next_read_size_hint = did_dispatch_message ? 0 : kReadBufferSize; 667 return true; 668 } 669 670 void Channel::OnError() { 671 if (delegate_) 672 delegate_->OnChannelError(); 673 } 674 675 bool Channel::OnControlMessage(Message::MessageType message_type, 676 const void* payload, 677 size_t payload_size, 678 ScopedPlatformHandleVectorPtr handles) { 679 return false; 680 } 681 682 } // namespace edk 683 } // namespace mojo 684