ipc_message_utils.cc (4126B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "chrome/common/ipc_message_utils.h" 8 #include "mozilla/ipc/SharedMemoryCursor.h" 9 10 namespace IPC { 11 12 MessageBufferWriter::MessageBufferWriter(MessageWriter* writer, 13 uint32_t full_len) 14 : writer_(writer) { 15 // NOTE: We only write out the `shmem_ok` bool if we're over 16 // kMessageBufferShmemThreshold to avoid bloating the size of messages with 17 // small buffers. 18 if (full_len > kMessageBufferShmemThreshold) { 19 auto handle = mozilla::ipc::shared_memory::Create(full_len); 20 bool shmem_ok = handle.IsValid(); 21 writer->WriteBool(shmem_ok); 22 if (shmem_ok) { 23 shmem_cursor_ = mozilla::MakeUnique<mozilla::ipc::shared_memory::Cursor>( 24 std::move(handle)); 25 MOZ_ASSERT(shmem_cursor_->IsValid()); 26 } else { 27 writer->NoteLargeBufferShmemFailure(full_len); 28 } 29 } 30 remaining_ = full_len; 31 } 32 33 MessageBufferWriter::~MessageBufferWriter() { 34 if (remaining_ != 0) { 35 writer_->FatalError("didn't fully write message buffer"); 36 } 37 38 // We couldn't write out the shared memory region until now, as the cursor 39 // needs to hold on to the handle to potentially re-map sub-regions while 40 // writing. 41 if (shmem_cursor_) { 42 IPC::WriteParam(writer_, shmem_cursor_->TakeHandle()); 43 } 44 } 45 46 bool MessageBufferWriter::WriteBytes(const void* data, uint32_t len) { 47 MOZ_RELEASE_ASSERT(len == remaining_ || (len % 4) == 0, 48 "all writes except for the final write must be a multiple " 49 "of 4 bytes in length due to padding"); 50 if (len > remaining_) { 51 writer_->FatalError("MessageBufferWriter overrun"); 52 return false; 53 } 54 remaining_ -= len; 55 // If we're serializing using a shared memory region, `shmem_cursor_` will be 56 // initialized. 57 if (shmem_cursor_) { 58 return shmem_cursor_->Write(data, len); 59 } 60 return writer_->WriteBytes(data, len); 61 } 62 63 MessageBufferReader::MessageBufferReader(MessageReader* reader, 64 uint32_t full_len) 65 : reader_(reader) { 66 // NOTE: We only write out the `shmem_ok` bool if we're over 67 // kMessageBufferShmemThreshold to avoid bloating the size of messages with 68 // small buffers. 69 if (full_len > kMessageBufferShmemThreshold) { 70 bool shmem_ok = false; 71 if (!reader->ReadBool(&shmem_ok)) { 72 reader->FatalError("MessageReader::ReadBool failed!"); 73 return; 74 } 75 if (shmem_ok) { 76 mozilla::ipc::shared_memory::MutableHandle handle; 77 if (!IPC::ReadParam(reader, &handle)) { 78 reader->FatalError("failed to read shared memory handle"); 79 return; 80 } 81 if (!handle.IsValid()) { 82 reader->FatalError("invalid shared memory handle"); 83 return; 84 } 85 if (handle.Size() < full_len) { 86 reader->FatalError("too small shared memory handle"); 87 return; 88 } 89 shmem_cursor_ = mozilla::MakeUnique<mozilla::ipc::shared_memory::Cursor>( 90 std::move(handle)); 91 MOZ_ASSERT(shmem_cursor_->IsValid()); 92 } 93 } 94 remaining_ = full_len; 95 } 96 97 MessageBufferReader::~MessageBufferReader() { 98 if (remaining_ != 0) { 99 reader_->FatalError("didn't fully write message buffer"); 100 } 101 } 102 103 bool MessageBufferReader::ReadBytesInto(void* data, uint32_t len) { 104 MOZ_RELEASE_ASSERT(len == remaining_ || (len % 4) == 0, 105 "all reads except for the final read must be a multiple " 106 "of 4 bytes in length due to padding"); 107 if (len > remaining_) { 108 reader_->FatalError("MessageBufferReader overrun"); 109 return false; 110 } 111 remaining_ -= len; 112 // If we're serializing using a shared memory region, `shmem_cursor_` will be 113 // initialized. 114 if (shmem_cursor_) { 115 return shmem_cursor_->Read(data, len); 116 } 117 return reader_->ReadBytesInto(data, len); 118 } 119 120 } // namespace IPC