blob: 0aca5e7bbc91e513340ce431c86e9b314d345141 [file] [log] [blame]
Primiano Tucci9ebb8822017-11-09 18:36:25 +00001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef IPC_SRC_BUFFERED_FRAME_DESERIALIZER_H_
18#define IPC_SRC_BUFFERED_FRAME_DESERIALIZER_H_
19
20#include <stddef.h>
21
22#include <list>
23#include <memory>
24
25#include "base/utils.h"
26
27namespace perfetto {
28namespace ipc {
29
30class Frame; // Defined in the protobuf autogenerated wire_protocol.pb.h.
31
32// Deserializes incoming frames, taking care of buffering and tokenization.
33// Used by both host and client to decode incoming frames.
34//
35// Which problem does it solve?
36// ----------------------------
37// The wire protocol is as follows:
38// [32-bit frame size][proto-encoded Frame], e.g:
39// [06 00 00 00][00 11 22 33 44 55 66]
40// [02 00 00 00][AA BB]
41// [04 00 00 00][CC DD EE FF]
42// However, given that the socket works in SOCK_STREAM mode, the recv() calls
43// might see the following:
44// 06 00 00
45// 00 00 11 22 33 44 55
46// 66 02 00 00 00 ...
47// This class takes care of buffering efficiently the data received, without
48// making any assumption on how the incoming data will be chunked by the socket.
49// For instance, it is possible that a recv() doesn't produce any frame (because
50// it received only a part of the frame) or produces more than one frame.
51//
52// Usage
53// -----
54// Both host and client use this as follows:
55//
56// auto buf = rpc_frame_decoder.BeginReceive();
57// size_t rsize = socket.recv(buf.first, buf.second);
58// rpc_frame_decoder.EndReceive(rsize);
59// while (Frame frame = rpc_frame_decoder.PopNextFrame()) {
60// ... process |frame|
61// }
62//
63// Design goals:
64// -------------
65// - Optimize for the realistic case of each recv() receiving one or more
66// whole frames. In this case no memmove is performed.
67// - Guarantee that frames lay in a virtually contiguous memory area.
68// This allows to use the protobuf-lite deserialization API (scattered
69// deserialization is supported only by libprotobuf-full).
70// - Put a hard boundary to the size of the incoming buffer. This is to prevent
71// that a malicious sends an abnormally large frame and OOMs us.
72// - Simplicity: just use a linear mmap region. No reallocations or scattering.
73// Takes care of madvise()-ing unused memory.
74
75class BufferedFrameDeserializer {
76 public:
77 struct ReceiveBuffer {
78 char* data;
79 size_t size;
80 };
81
82 explicit BufferedFrameDeserializer(size_t max_capacity = 128 * 1024);
83 ~BufferedFrameDeserializer();
84
Primiano Tuccied0ce252017-11-09 19:35:10 +000085 // This function doesn't really belong here as it does Serialization, unlike
86 // the rest of this class. However it is so small and has so many dependencies
87 // in common that doesn't justify having its own class.
88 static std::string Serialize(const Frame&);
89
Primiano Tucci9ebb8822017-11-09 18:36:25 +000090 // Returns a buffer that can be passed to recv(). The buffer is deliberately
91 // not initialized.
92 ReceiveBuffer BeginReceive();
93
94 // Must be called soon after BeginReceive().
95 // |recv_size| is the number of valid bytes that have been written into the
96 // buffer previously returned by BeginReceive() (the return value of recv()).
97 // Returns false if a header > |max_capacity| is received, in which case the
98 // caller is expected to shutdown the socket and terminate the ipc.
99 bool EndReceive(size_t recv_size) __attribute__((warn_unused_result));
100
101 // Decodes and returns the next decoded frame in the buffer if any, nullptr
102 // if no further frames have been decoded.
103 std::unique_ptr<Frame> PopNextFrame();
104
105 size_t capacity() const { return capacity_; }
106 size_t size() const { return size_; }
107
108 private:
109 BufferedFrameDeserializer(const BufferedFrameDeserializer&) = delete;
110 BufferedFrameDeserializer& operator=(const BufferedFrameDeserializer&) =
111 delete;
112
113 // If a valid frame is decoded it is added to |decoded_frames_|.
114 void DecodeFrame(const char*, size_t);
115
116 char* buf_ = nullptr;
117 const size_t capacity_ = 0; // sizeof(|buf_|), excluding the guard region.
118
119 // THe number of bytes in |buf_| that contain valid data (as a result of
120 // EndReceive()). This is always <= |capacity_|.
121 size_t size_ = 0;
122
123 std::list<std::unique_ptr<Frame>> decoded_frames_;
124};
125
126} // namespace ipc
127} // namespace perfetto
128
129#endif // IPC_SRC_BUFFERED_FRAME_DESERIALIZER_H_