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