OLD | NEW |
| (Empty) |
1 // Copyright 2014 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 "components/cast_channel/cast_framer.h" | |
6 | |
7 #include <stdlib.h> | |
8 | |
9 #include <limits> | |
10 | |
11 #include "base/memory/free_deleter.h" | |
12 #include "base/numerics/safe_conversions.h" | |
13 #include "base/strings/string_number_conversions.h" | |
14 #include "base/sys_byteorder.h" | |
15 #include "components/cast_channel/proto/cast_channel.pb.h" | |
16 | |
17 namespace cast_channel { | |
18 MessageFramer::MessageFramer(scoped_refptr<net::GrowableIOBuffer> input_buffer) | |
19 : input_buffer_(input_buffer), error_(false) { | |
20 Reset(); | |
21 } | |
22 | |
23 MessageFramer::~MessageFramer() {} | |
24 | |
25 MessageFramer::MessageHeader::MessageHeader() : message_size(0) {} | |
26 | |
27 void MessageFramer::MessageHeader::SetMessageSize(size_t size) { | |
28 DCHECK_LT(size, static_cast<size_t>(std::numeric_limits<uint32_t>::max())); | |
29 DCHECK_GT(size, 0U); | |
30 message_size = size; | |
31 } | |
32 | |
33 // TODO(mfoltz): Investigate replacing header serialization with base::Pickle, | |
34 // if bit-for-bit compatible. | |
35 void MessageFramer::MessageHeader::PrependToString(std::string* str) { | |
36 MessageHeader output = *this; | |
37 output.message_size = base::HostToNet32(message_size); | |
38 size_t header_size = MessageHeader::header_size(); | |
39 std::unique_ptr<char, base::FreeDeleter> char_array( | |
40 static_cast<char*>(malloc(header_size))); | |
41 memcpy(char_array.get(), &output, header_size); | |
42 str->insert(0, char_array.get(), header_size); | |
43 } | |
44 | |
45 // TODO(mfoltz): Investigate replacing header deserialization with base::Pickle, | |
46 // if bit-for-bit compatible. | |
47 void MessageFramer::MessageHeader::Deserialize(char* data, | |
48 MessageHeader* header) { | |
49 uint32_t message_size; | |
50 memcpy(&message_size, data, header_size()); | |
51 header->message_size = | |
52 base::checked_cast<size_t>(base::NetToHost32(message_size)); | |
53 } | |
54 | |
55 // static | |
56 size_t MessageFramer::MessageHeader::header_size() { | |
57 return sizeof(uint32_t); | |
58 } | |
59 | |
60 // static | |
61 size_t MessageFramer::MessageHeader::max_message_size() { | |
62 return 65535; | |
63 } | |
64 | |
65 std::string MessageFramer::MessageHeader::ToString() { | |
66 return "{message_size: " + | |
67 base::UintToString(static_cast<uint32_t>(message_size)) + "}"; | |
68 } | |
69 | |
70 // static | |
71 bool MessageFramer::Serialize(const CastMessage& message_proto, | |
72 std::string* message_data) { | |
73 DCHECK(message_data); | |
74 message_proto.SerializeToString(message_data); | |
75 size_t message_size = message_data->size(); | |
76 if (message_size > MessageHeader::max_message_size()) { | |
77 message_data->clear(); | |
78 return false; | |
79 } | |
80 MessageHeader header; | |
81 header.SetMessageSize(message_size); | |
82 header.PrependToString(message_data); | |
83 return true; | |
84 } | |
85 | |
86 size_t MessageFramer::BytesRequested() { | |
87 size_t bytes_left; | |
88 if (error_) { | |
89 return 0; | |
90 } | |
91 | |
92 switch (current_element_) { | |
93 case HEADER: | |
94 bytes_left = MessageHeader::header_size() - message_bytes_received_; | |
95 DCHECK_LE(bytes_left, MessageHeader::header_size()); | |
96 VLOG(2) << "Bytes needed for header: " << bytes_left; | |
97 return bytes_left; | |
98 case BODY: | |
99 bytes_left = | |
100 (body_size_ + MessageHeader::header_size()) - message_bytes_received_; | |
101 DCHECK_LE(bytes_left, MessageHeader::max_message_size() - | |
102 MessageHeader::header_size()); | |
103 VLOG(2) << "Bytes needed for body: " << bytes_left; | |
104 return bytes_left; | |
105 default: | |
106 NOTREACHED() << "Unhandled packet element type."; | |
107 return 0; | |
108 } | |
109 } | |
110 | |
111 std::unique_ptr<CastMessage> MessageFramer::Ingest(size_t num_bytes, | |
112 size_t* message_length, | |
113 ChannelError* error) { | |
114 DCHECK(error); | |
115 DCHECK(message_length); | |
116 if (error_) { | |
117 *error = ChannelError::INVALID_MESSAGE; | |
118 return nullptr; | |
119 } | |
120 | |
121 DCHECK_EQ(base::checked_cast<int32_t>(message_bytes_received_), | |
122 input_buffer_->offset()); | |
123 CHECK_LE(num_bytes, BytesRequested()); | |
124 message_bytes_received_ += num_bytes; | |
125 *error = ChannelError::NONE; | |
126 *message_length = 0; | |
127 switch (current_element_) { | |
128 case HEADER: | |
129 if (BytesRequested() == 0) { | |
130 MessageHeader header; | |
131 MessageHeader::Deserialize(input_buffer_->StartOfBuffer(), &header); | |
132 if (header.message_size > MessageHeader::max_message_size()) { | |
133 VLOG(1) << "Error parsing header (message size too large)."; | |
134 *error = ChannelError::INVALID_MESSAGE; | |
135 error_ = true; | |
136 return nullptr; | |
137 } | |
138 current_element_ = BODY; | |
139 body_size_ = header.message_size; | |
140 } | |
141 break; | |
142 case BODY: | |
143 if (BytesRequested() == 0) { | |
144 std::unique_ptr<CastMessage> parsed_message(new CastMessage); | |
145 if (!parsed_message->ParseFromArray( | |
146 input_buffer_->StartOfBuffer() + MessageHeader::header_size(), | |
147 body_size_)) { | |
148 VLOG(1) << "Error parsing packet body."; | |
149 *error = ChannelError::INVALID_MESSAGE; | |
150 error_ = true; | |
151 return nullptr; | |
152 } | |
153 *message_length = body_size_; | |
154 Reset(); | |
155 return parsed_message; | |
156 } | |
157 break; | |
158 default: | |
159 NOTREACHED() << "Unhandled packet element type."; | |
160 return nullptr; | |
161 } | |
162 | |
163 input_buffer_->set_offset(message_bytes_received_); | |
164 return nullptr; | |
165 } | |
166 | |
167 void MessageFramer::Reset() { | |
168 current_element_ = HEADER; | |
169 message_bytes_received_ = 0; | |
170 body_size_ = 0; | |
171 input_buffer_->set_offset(0); | |
172 } | |
173 | |
174 } // namespace cast_channel | |
OLD | NEW |