Index: tools/battor_agent/battor_connection_impl.cc |
diff --git a/tools/battor_agent/battor_connection_impl.cc b/tools/battor_agent/battor_connection_impl.cc |
index 13568c93ba3d3bcc44e26c8950340d1d8646ff87..2c3ee830b2d4efee5c1a3da47cccb8c43c88b7fc 100644 |
--- a/tools/battor_agent/battor_connection_impl.cc |
+++ b/tools/battor_agent/battor_connection_impl.cc |
@@ -25,96 +25,21 @@ const device::serial::ParityBit kBattOrParityBit = |
const device::serial::StopBits kBattOrStopBit = device::serial::STOP_BITS_ONE; |
const bool kBattOrCtsFlowControl = true; |
const bool kBattOrHasCtsFlowControl = true; |
-const uint32_t kMaxMessageSize = 50000; |
- |
-// MessageHealth describes the possible healthiness states that a partially |
-// received message could be in. |
-enum class MessageHealth { |
- INVALID, |
- INCOMPLETE, |
- COMPLETE, |
-}; |
- |
-// Parses the specified message. |
-// - message: The incoming message that needs to be parsed. |
-// - parsed_content: Output argument for the message content after removal of |
-// any start, end, type, and escape bytes. |
-// - health: Output argument for the health of the message. |
-// - type: Output argument for the type of message being parsed. |
-// - escape_byte_count: Output argument for the number of escape bytes |
-// removed from the parsed content. |
-void ParseMessage(const vector<char>& message, |
- vector<char>* parsed_content, |
- MessageHealth* health, |
- BattOrMessageType* type, |
- size_t* escape_byte_count) { |
- *health = MessageHealth::INCOMPLETE; |
- *type = BATTOR_MESSAGE_TYPE_CONTROL; |
- *escape_byte_count = 0; |
- parsed_content->reserve(message.size()); |
- |
- if (message.size() == 0) |
- return; |
- |
- // The first byte is the start byte. |
- if (message[0] != BATTOR_CONTROL_BYTE_START) { |
- *health = MessageHealth::INVALID; |
- return; |
- } |
- |
- if (message.size() == 1) |
- return; |
- |
- // The second byte specifies the message type. |
- *type = static_cast<BattOrMessageType>(message[1]); |
- |
- if (*type < static_cast<uint8_t>(BATTOR_MESSAGE_TYPE_CONTROL) || |
- *type > static_cast<uint8_t>(BATTOR_MESSAGE_TYPE_PRINT)) { |
- *health = MessageHealth::INVALID; |
- return; |
- } |
- |
- // After that comes the message data. |
- bool escape_next_byte = false; |
- for (size_t i = 2; i < message.size(); i++) { |
- if (i >= kMaxMessageSize) { |
- *health = MessageHealth::INVALID; |
- return; |
- } |
- |
- char next_byte = message[i]; |
- |
- if (escape_next_byte) { |
- parsed_content->push_back(next_byte); |
- escape_next_byte = false; |
- continue; |
- } |
- |
- switch (next_byte) { |
- case BATTOR_CONTROL_BYTE_START: |
- // Two start bytes in a message is invalid. |
- *health = MessageHealth::INVALID; |
- return; |
- |
- case BATTOR_CONTROL_BYTE_END: |
- if (i != message.size() - 1) { |
- // We're only parsing a single message here. If we received more bytes |
- // after the end byte, what we've received so far is *not* valid. |
- *health = MessageHealth::INVALID; |
- return; |
- } |
- |
- *health = MessageHealth::COMPLETE; |
- return; |
- |
- case BATTOR_CONTROL_BYTE_ESCAPE: |
- escape_next_byte = true; |
- (*escape_byte_count)++; |
- continue; |
- |
- default: |
- parsed_content->push_back(next_byte); |
- } |
+// The maximum BattOr message is 50kB long. |
+const size_t kMaxMessageSizeBytes = 50000; |
+ |
+// Returns the maximum number of bytes that could be required to read a message |
+// of the specified type. |
+size_t GetMaxBytesForMessageType(BattOrMessageType type) { |
+ switch (type) { |
+ case BATTOR_MESSAGE_TYPE_CONTROL: |
+ return 2 * sizeof(BattOrControlMessage) + 3; |
+ case BATTOR_MESSAGE_TYPE_CONTROL_ACK: |
+ return 2 * sizeof(BattOrControlMessageAck) + 3; |
+ case BATTOR_MESSAGE_TYPE_SAMPLES: |
+ return 2 * kMaxMessageSizeBytes + 3; |
+ default: |
+ return 0; |
} |
} |
@@ -168,9 +93,8 @@ void BattOrConnectionImpl::SendBytes(BattOrMessageType type, |
size_t bytes_to_send) { |
const char* bytes = reinterpret_cast<const char*>(buffer); |
- // Reserve a send buffer with 3 extra bytes (start, type, and end byte) and |
- // twice as many bytes as we're actually sending, because each raw data byte |
- // might need to be escaped. |
+ // Reserve a send buffer with enough extra bytes for the start, type, end, and |
+ // escape bytes. |
vector<char> data; |
data.reserve(2 * bytes_to_send + 3); |
@@ -193,22 +117,27 @@ void BattOrConnectionImpl::SendBytes(BattOrMessageType type, |
data, base::Bind(&BattOrConnectionImpl::OnBytesSent, AsWeakPtr())))); |
} |
-void BattOrConnectionImpl::ReadBytes(size_t bytes_to_read) { |
- // Allocate a read buffer and reserve enough space in it to account for the |
- // start, type, end, and escape bytes. |
- pending_read_buffer_.reset(new vector<char>()); |
- pending_read_buffer_->reserve(2 * bytes_to_read + 3); |
- pending_read_escape_byte_count_ = 0; |
+void BattOrConnectionImpl::ReadMessage(BattOrMessageType type) { |
+ pending_read_message_type_ = type; |
+ size_t max_bytes_to_read = GetMaxBytesForMessageType(type); |
+ |
+ // Check the left-over bytes from the last read to make sure that we don't |
+ // already have a full message. |
+ BattOrMessageType parsed_type; |
+ scoped_ptr<vector<char>> bytes(new vector<char>()); |
+ bytes->reserve(max_bytes_to_read); |
- // Add 3 bytes to however many bytes the caller requested because we know |
- // we'll have to read the start, type, and end bytes. |
- bytes_to_read += 3; |
+ if (ParseMessage(&parsed_type, bytes.get())) { |
+ listener_->OnMessageRead(true, parsed_type, std::move(bytes)); |
+ return; |
+ } |
- ReadMoreBytes(bytes_to_read); |
+ BeginReadBytes(max_bytes_to_read - already_read_buffer_.size()); |
} |
void BattOrConnectionImpl::Flush() { |
io_handler_->Flush(); |
+ already_read_buffer_.clear(); |
} |
scoped_refptr<device::SerialIoHandler> BattOrConnectionImpl::CreateIoHandler() { |
@@ -216,62 +145,109 @@ scoped_refptr<device::SerialIoHandler> BattOrConnectionImpl::CreateIoHandler() { |
ui_thread_task_runner_); |
} |
-void BattOrConnectionImpl::ReadMoreBytes(size_t bytes_to_read) { |
- last_read_buffer_ = make_scoped_refptr(new net::IOBuffer(bytes_to_read)); |
+void BattOrConnectionImpl::BeginReadBytes(size_t max_bytes_to_read) { |
+ pending_read_buffer_ = |
+ make_scoped_refptr(new net::IOBuffer(max_bytes_to_read)); |
+ |
auto on_receive_buffer_filled = |
base::Bind(&BattOrConnectionImpl::OnBytesRead, AsWeakPtr()); |
- pending_read_length_ = bytes_to_read; |
io_handler_->Read(make_scoped_ptr(new device::ReceiveBuffer( |
- last_read_buffer_, bytes_to_read, on_receive_buffer_filled))); |
+ pending_read_buffer_, max_bytes_to_read, on_receive_buffer_filled))); |
} |
void BattOrConnectionImpl::OnBytesRead(int bytes_read, |
device::serial::ReceiveError error) { |
- if ((static_cast<size_t>(bytes_read) < pending_read_length_) || |
- (error != device::serial::RECEIVE_ERROR_NONE)) { |
- listener_->OnBytesRead(false, BATTOR_MESSAGE_TYPE_CONTROL, nullptr); |
+ if (bytes_read == 0 || error != device::serial::RECEIVE_ERROR_NONE) { |
+ // If we didn't have a message before, and we weren't able to read any |
+ // additional bytes, then there's no valid message available. |
+ EndReadBytes(false, BATTOR_MESSAGE_TYPE_CONTROL, nullptr); |
return; |
} |
- pending_read_buffer_->insert(pending_read_buffer_->end(), |
- last_read_buffer_->data(), |
- last_read_buffer_->data() + bytes_read); |
+ already_read_buffer_.insert(already_read_buffer_.end(), |
+ pending_read_buffer_->data(), |
+ pending_read_buffer_->data() + bytes_read); |
- scoped_ptr<vector<char>> parsed_content(new vector<char>()); |
- MessageHealth health; |
BattOrMessageType type; |
- size_t escape_byte_count; |
+ scoped_ptr<vector<char>> bytes(new vector<char>()); |
+ bytes->reserve(GetMaxBytesForMessageType(pending_read_message_type_)); |
- ParseMessage(*pending_read_buffer_, parsed_content.get(), &health, &type, |
- &escape_byte_count); |
+ if (!ParseMessage(&type, bytes.get())) { |
+ // Even after reading the max number of bytes, we still don't have a valid |
+ // message. |
+ EndReadBytes(false, BATTOR_MESSAGE_TYPE_CONTROL, nullptr); |
+ return; |
+ } |
- if (health == MessageHealth::INVALID) { |
- // If we already have an invalid message, there's no sense in continuing to |
- // process it. |
- listener_->OnBytesRead(false, BATTOR_MESSAGE_TYPE_CONTROL, nullptr); |
+ if (type != pending_read_message_type_) { |
+ // We received a complete message, but it wasn't the type we were expecting. |
+ EndReadBytes(false, BATTOR_MESSAGE_TYPE_CONTROL, nullptr); |
return; |
} |
- size_t new_escape_bytes = escape_byte_count - pending_read_escape_byte_count_; |
- pending_read_escape_byte_count_ = escape_byte_count; |
+ EndReadBytes(true, type, std::move(bytes)); |
+} |
- if (new_escape_bytes > 0) { |
- // When the caller requested that we read X additional bytes, they weren't |
- // taking into account any escape bytes that we received. Because we got |
- // some escape bytes, we need to fire off another read to get the rest of |
- // the data. |
- ReadMoreBytes(new_escape_bytes); |
- return; |
+void BattOrConnectionImpl::EndReadBytes(bool success, |
+ BattOrMessageType type, |
+ scoped_ptr<std::vector<char>> bytes) { |
+ pending_read_buffer_ = nullptr; |
+ |
+ listener_->OnMessageRead(success, type, std::move(bytes)); |
+} |
+ |
+bool BattOrConnectionImpl::ParseMessage(BattOrMessageType* type, |
+ vector<char>* bytes) { |
+ if (already_read_buffer_.size() <= 3) |
+ return false; |
+ |
+ // The first byte is the start byte. |
+ if (already_read_buffer_[0] != BATTOR_CONTROL_BYTE_START) { |
+ return false; |
} |
- if (health == MessageHealth::INCOMPLETE) |
- // If everything is valid and we didn't see any escape bytes, then we should |
- // have the whole message. If we don't, the message was malformed. |
- listener_->OnBytesRead(false, BATTOR_MESSAGE_TYPE_CONTROL, nullptr); |
+ // The second byte specifies the message type. |
+ *type = static_cast<BattOrMessageType>(already_read_buffer_[1]); |
+ |
+ if (*type < static_cast<uint8_t>(BATTOR_MESSAGE_TYPE_CONTROL) || |
+ *type > static_cast<uint8_t>(BATTOR_MESSAGE_TYPE_PRINT)) { |
+ return false; |
+ } |
+ |
+ // After that comes the message bytes. |
+ bool escape_next_byte = false; |
+ for (size_t i = 2; i < already_read_buffer_.size(); i++) { |
+ char next_byte = already_read_buffer_[i]; |
+ |
+ if (escape_next_byte) { |
+ bytes->push_back(next_byte); |
+ escape_next_byte = false; |
+ continue; |
+ } |
+ |
+ switch (next_byte) { |
+ case BATTOR_CONTROL_BYTE_START: |
+ // Two start bytes in a message is invalid. |
+ return false; |
+ |
+ case BATTOR_CONTROL_BYTE_END: |
+ already_read_buffer_.erase(already_read_buffer_.begin(), |
+ already_read_buffer_.begin() + i + 1); |
+ return true; |
+ |
+ case BATTOR_CONTROL_BYTE_ESCAPE: |
+ escape_next_byte = true; |
+ continue; |
+ |
+ default: |
+ bytes->push_back(next_byte); |
+ } |
+ } |
- // If we've gotten this far, we've received the whole, well-formed message. |
- listener_->OnBytesRead(true, type, std::move(parsed_content)); |
+ // If we made it to the end of the read buffer and no end byte was seen, then |
+ // we don't have a complete message. |
+ return false; |
} |
void BattOrConnectionImpl::OnBytesSent(int bytes_sent, |