Adding SmartBuffer class used for packing socket messages
BUG=chromium:885915
TEST=Added unit tests for SmartBuffer class
Change-Id: I2953ad84da30c47f5d439115fe08c595c931a3b7
Reviewed-on: https://chromium-review.googlesource.com/1374371
Commit-Ready: David Valleau <valleau@chromium.org>
Tested-by: David Valleau <valleau@chromium.org>
Reviewed-by: Sean Kau <skau@chromium.org>
diff --git a/device_descriptors.h b/device_descriptors.h
index 607dbf6..ad39544 100644
--- a/device_descriptors.h
+++ b/device_descriptors.h
@@ -28,6 +28,7 @@
bDescriptorType(_bDescriptorType),
bcdUSB(_bcdUSB),
bDeviceClass(_bDeviceClass),
+ bDeviceSubClass(_bDeviceSubClass),
bDeviceProtocol(_bDeviceProtocol),
bMaxPacketSize0(_bMaxPacketSize0),
idVendor(_idVendor),
diff --git a/op_commands.cc b/op_commands.cc
index f232c33..8780b26 100644
--- a/op_commands.cc
+++ b/op_commands.cc
@@ -94,55 +94,55 @@
SetOpRepDevice(dev_dsc, config, &rep->device);
}
-SmartBuffer<uint8_t> PackOpHeader(OpHeader header) {
+SmartBuffer PackOpHeader(OpHeader header) {
header.version = htons(header.version);
header.command = htons(header.command);
header.status = htonl(header.status);
- SmartBuffer<uint8_t> packed_header(sizeof(header));
+ SmartBuffer packed_header(sizeof(header));
packed_header.Add(&header, sizeof(header));
return packed_header;
}
-SmartBuffer<uint8_t> PackOpRepDevice(OpRepDevice device) {
+SmartBuffer PackOpRepDevice(OpRepDevice device) {
device.busnum = htonl(device.busnum);
device.devnum = htonl(device.devnum);
device.speed = htonl(device.speed);
device.idVendor = htons(device.idVendor);
device.idProduct = htons(device.idProduct);
device.bcdDevice = htons(device.bcdDevice);
- SmartBuffer<uint8_t> packed_device(sizeof(device));
+ SmartBuffer packed_device(sizeof(device));
packed_device.Add(&device, sizeof(device));
return packed_device;
}
-SmartBuffer<uint8_t> PackOpRepDevlistHeader(OpRepDevlistHeader devlist_header) {
- SmartBuffer<uint8_t> packed_op_header = PackOpHeader(devlist_header.header);
+SmartBuffer PackOpRepDevlistHeader(OpRepDevlistHeader devlist_header) {
+ SmartBuffer packed_op_header = PackOpHeader(devlist_header.header);
devlist_header.numExportedDevices = htonl(devlist_header.numExportedDevices);
- SmartBuffer<uint8_t> packed_header(sizeof(OpRepDevlistHeader));
+ SmartBuffer packed_header(sizeof(OpRepDevlistHeader));
packed_header.Add(packed_op_header);
packed_header.Add(&devlist_header.numExportedDevices,
sizeof(devlist_header.numExportedDevices));
return packed_header;
}
-SmartBuffer<uint8_t> PackOpRepDevlist(OpRepDevlist devlist) {
- SmartBuffer<uint8_t> packed_header = PackOpRepDevlistHeader(devlist.header);
- SmartBuffer<uint8_t> packed_device = PackOpRepDevice(devlist.device);
+SmartBuffer PackOpRepDevlist(OpRepDevlist devlist) {
+ SmartBuffer packed_header = PackOpRepDevlistHeader(devlist.header);
+ SmartBuffer packed_device = PackOpRepDevice(devlist.device);
size_t interfaces_size =
sizeof(*devlist.interfaces) * devlist.device.bNumInterfaces;
size_t buffer_size =
sizeof(devlist.header) + sizeof(devlist.device) + interfaces_size;
- SmartBuffer<uint8_t> packed_devlist(buffer_size);
+ SmartBuffer packed_devlist(buffer_size);
packed_devlist.Add(packed_header);
packed_devlist.Add(packed_device);
packed_devlist.Add(devlist.interfaces, interfaces_size);
return packed_devlist;
}
-SmartBuffer<uint8_t> PackOpRepImport(OpRepImport import) {
- SmartBuffer<uint8_t> packed_header = PackOpHeader(import.header);
- SmartBuffer<uint8_t> packed_device = PackOpRepDevice(import.device);
- SmartBuffer<uint8_t> packed_import(sizeof(import));
+SmartBuffer PackOpRepImport(OpRepImport import) {
+ SmartBuffer packed_header = PackOpHeader(import.header);
+ SmartBuffer packed_device = PackOpRepDevice(import.device);
+ SmartBuffer packed_import(sizeof(import));
packed_import.Add(packed_header);
packed_import.Add(packed_device);
return packed_import;
diff --git a/op_commands.h b/op_commands.h
index 2b01e70..81d2db1 100644
--- a/op_commands.h
+++ b/op_commands.h
@@ -129,11 +129,11 @@
// Convert the various elements of an "OpRep" message into network
// byte order and pack them into a SmartBuffer to be used for transferring along
// a socket.
-SmartBuffer<uint8_t> PackOpHeader(OpHeader header);
-SmartBuffer<uint8_t> PackOpRepDevice(OpRepDevice device);
-SmartBuffer<uint8_t> PackOpRepDevlistHeader(OpRepDevlistHeader devlist_header);
-SmartBuffer<uint8_t> PackOpRepDevlist(OpRepDevlist devlist);
-SmartBuffer<uint8_t> PackOpRepImport(OpRepImport import);
+SmartBuffer PackOpHeader(OpHeader header);
+SmartBuffer PackOpRepDevice(OpRepDevice device);
+SmartBuffer PackOpRepDevlistHeader(OpRepDevlistHeader devlist_header);
+SmartBuffer PackOpRepDevlist(OpRepDevlist devlist);
+SmartBuffer PackOpRepImport(OpRepImport import);
// Convert |header| into host uint8_t order.
void UnpackOpHeader(OpHeader* header);
diff --git a/server.cc b/server.cc
index 688629e..70c21a9 100644
--- a/server.cc
+++ b/server.cc
@@ -53,7 +53,7 @@
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = htons(TCP_SERV_PORT);
- if (bind(fd, (sockaddr *)&server, sizeof(server)) < 0) {
+ if (bind(fd, (sockaddr*)&server, sizeof(server)) < 0) {
LOG(ERROR) << "Bind error: " << strerror(errno);
exit(1);
}
@@ -87,7 +87,7 @@
}
}
-void SendBuffer(int sockfd, const SmartBuffer<uint8_t>& smart_buffer) {
+void SendBuffer(int sockfd, const SmartBuffer& smart_buffer) {
size_t remaining = smart_buffer.size();
size_t total = 0;
while (remaining > 0) {
@@ -104,8 +104,8 @@
LOG(INFO) << "Sent " << total << " bytes total";
}
-SmartBuffer<uint8_t> ReceiveBuffer(int sockfd, size_t size) {
- SmartBuffer<uint8_t> smart_buffer(size);
+SmartBuffer ReceiveBuffer(int sockfd, size_t size) {
+ SmartBuffer smart_buffer(size);
auto buf = std::make_unique<uint8_t[]>(size);
size_t remaining = size;
size_t total = 0;
@@ -128,7 +128,7 @@
CreateOpRepDevlist(printer.device_descriptor(),
printer.configuration_descriptor(), printer.interfaces(),
&list);
- SmartBuffer<uint8_t> packed_devlist = PackOpRepDevlist(list);
+ SmartBuffer packed_devlist = PackOpRepDevlist(list);
free(list.interfaces);
SendBuffer(sockfd, packed_devlist);
}
@@ -147,12 +147,11 @@
OpRepImport rep;
CreateOpRepImport(printer.device_descriptor(),
printer.configuration_descriptor(), &rep);
- SmartBuffer<uint8_t> packed_import = PackOpRepImport(rep);
+ SmartBuffer packed_import = PackOpRepImport(rep);
SendBuffer(sockfd, packed_import);
}
-bool HandleOpRequest(const UsbPrinter& printer,
- int connection,
+bool HandleOpRequest(const UsbPrinter& printer, int connection,
bool* attached) {
// Read in the header first in order to determine whether the request is an
// OpReqDevlist or an OpReqImport.
diff --git a/server.h b/server.h
index 35a0192..943e03b 100644
--- a/server.h
+++ b/server.h
@@ -25,8 +25,8 @@
// format.
void ReportBoundAddress(struct sockaddr_in* server);
-void SendBuffer(int sockfd, const SmartBuffer<uint8_t>& smart_buffer);
-SmartBuffer<uint8_t> ReceiveBuffer(int sockfd, size_t size);
+void SendBuffer(int sockfd, const SmartBuffer& smart_buffer);
+SmartBuffer ReceiveBuffer(int sockfd, size_t size);
// Handles an OpReqDevlist request using |printer| to create an OpRepDevlist
// message.
diff --git a/smart_buffer.cc b/smart_buffer.cc
new file mode 100644
index 0000000..d9ea3e6
--- /dev/null
+++ b/smart_buffer.cc
@@ -0,0 +1,57 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "smart_buffer.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <base/logging.h>
+
+SmartBuffer::SmartBuffer(size_t size) {
+ // Set the capacity of |buffer_| to |size|.
+ buffer_.reserve(size);
+}
+
+SmartBuffer::SmartBuffer(const std::vector<uint8_t>& v) : buffer_(v) {}
+
+void SmartBuffer::Add(const std::string& s) {
+ Add(s.c_str(), s.size());
+}
+
+// Adds the contents from |buf|.
+void SmartBuffer::Add(const SmartBuffer& buf) {
+ const std::vector<uint8_t> contents = buf.contents();
+ buffer_.insert(buffer_.end(), contents.begin(), contents.end());
+}
+
+// Add the contents from |buf|, starting from |start|.
+void SmartBuffer::Add(const SmartBuffer& buf, size_t start) {
+ const std::vector<uint8_t>& contents = buf.contents();
+ buffer_.insert(buffer_.end(), contents.begin() + start, contents.end());
+}
+
+void SmartBuffer::Add(const SmartBuffer& buf, size_t start, size_t len) {
+ CHECK_LE(start + len, buf.size()) << "Given range out of bounds";
+ const std::vector<uint8_t>& contents = buf.contents();
+ buffer_.insert(buffer_.end(), contents.begin() + start,
+ contents.begin() + start + len);
+}
+
+void SmartBuffer::Erase(size_t index) {
+ buffer_.erase(buffer_.begin() + index);
+}
+
+void SmartBuffer::Erase(size_t start, size_t len) {
+ buffer_.erase(buffer_.begin() + start, buffer_.begin() + start + len);
+}
+
+void SmartBuffer::Shrink(size_t size) {
+ if (size >= buffer_.size()) {
+ LOG(INFO) << "Can't shrink to a size larger than current buffer";
+ return;
+ }
+ buffer_.resize(size);
+}
diff --git a/smart_buffer.h b/smart_buffer.h
new file mode 100644
index 0000000..7d866b1
--- /dev/null
+++ b/smart_buffer.h
@@ -0,0 +1,88 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef __SMART_BUFFER_H__
+#define __SMART_BUFFER_H__
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <base/logging.h>
+
+// Wrapper class used for packing bytes to be transferred on a network socket.
+class SmartBuffer {
+ public:
+ SmartBuffer() = default;
+
+ // Initialize the buffer with an initial size of |size|.
+ explicit SmartBuffer(size_t size);
+
+ // Initialize the buffer with the same contents as |v|.
+ explicit SmartBuffer(const std::vector<uint8_t>& v);
+
+ // Convert |data| into uint8_t* and add |data_size| bytes to the internal
+ // buffer.
+ template <typename T>
+ void Add(const T* data, size_t data_size);
+
+ // Add the underlying byte representation of |data| to the buffer.
+ template <typename T>
+ void Add(const T& data);
+
+ // Specialized Add method for std::vector so that we can call |v.data()| and
+ // |v.size()| to extract the underlying pointer and size of the data.
+ template <typename T>
+ void Add(const std::vector<T>& v);
+
+ // Specialized Add method for std::string so that we can call |s.c_str()| and
+ // |s.size()| to extract the underlying pointer and size of the data.
+ void Add(const std::string& s);
+
+ // Adds the contents from |buf|.
+ void Add(const SmartBuffer& buf);
+
+ // Add the contents from |buf|, starting from |start|.
+ void Add(const SmartBuffer& buf, size_t start);
+
+ // Add the subsequence of |buf| starting at |start| and of length |len|.
+ void Add(const SmartBuffer& buf, size_t start, size_t len);
+
+ // Erases the element at |index|.
+ void Erase(size_t index);
+
+ // Erases the subsequence of length |len| starting at |start| from |buffer|.
+ void Erase(size_t start, size_t len);
+
+ // Shrink the underlying vector to |size|.
+ void Shrink(size_t size);
+
+ size_t size() const { return buffer_.size(); }
+ const std::vector<uint8_t>& contents() const { return buffer_; }
+ const uint8_t* data() const { return buffer_.data(); }
+
+ private:
+ std::vector<uint8_t> buffer_;
+};
+
+template <typename T>
+void SmartBuffer::Add(const T* data, size_t data_size) {
+ const uint8_t* packed_data = reinterpret_cast<const uint8_t*>(data);
+ buffer_.insert(buffer_.end(), packed_data, packed_data + data_size);
+}
+
+template <typename T>
+void SmartBuffer::Add(const T& data) {
+ Add(&data, sizeof(data));
+}
+
+template <typename T>
+void SmartBuffer::Add(const std::vector<T>& v) {
+ CHECK(std::is_fundamental<T>::value)
+ << "Given vector does not contain fundamental elements";
+ size_t byte_size = sizeof(T) * v.size();
+ Add(v.data(), byte_size);
+}
+
+#endif // __SMART_BUFFER_H__
diff --git a/smart_buffer_test.cc b/smart_buffer_test.cc
new file mode 100644
index 0000000..d08a36a
--- /dev/null
+++ b/smart_buffer_test.cc
@@ -0,0 +1,122 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "smart_buffer.h"
+
+#include "device_descriptors.h"
+
+#include <vector>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace {
+
+TEST(Add, AddPrimitive) {
+ SmartBuffer buf1(1);
+ SmartBuffer buf2(1);
+ std::vector<uint8_t> expected = {'h'};
+ uint8_t byte = 'h';
+
+ buf1.Add(&byte, sizeof(byte));
+ EXPECT_EQ(expected, buf1.contents());
+ buf2.Add(byte);
+ EXPECT_EQ(expected, buf2.contents());
+}
+
+TEST(Add, AddVector) {
+ SmartBuffer buf1(5);
+ SmartBuffer buf2(5);
+ std::vector<uint8_t> expected = {1, 2, 3, 4, 5};
+
+ buf1.Add(expected.data(), expected.size());
+ EXPECT_EQ(expected, buf1.contents());
+ buf2.Add(expected);
+ EXPECT_EQ(expected, buf2.contents());
+}
+
+TEST(Add, AddString) {
+ SmartBuffer buf1(10);
+ SmartBuffer buf2(10);
+ std::string s = "helloworld";
+ std::vector<uint8_t> expected = {'h', 'e', 'l', 'l', 'o',
+ 'w', 'o', 'r', 'l', 'd'};
+ buf1.Add(s.c_str(), s.size());
+ EXPECT_EQ(expected, buf1.contents());
+ buf2.Add(s);
+ EXPECT_EQ(expected, buf2.contents());
+}
+
+TEST(Add, AddDeviceDescriptor) {
+ UsbDeviceDescriptor dev_dsc(18, 1, 272, 0, 0, 0, 8, 1193, 10216, 0, 1, 2, 1,
+ 1);
+ std::vector<uint8_t> expected = {18, 1, 16, 1, 0, 0, 0, 8,
+ 169, 4, 232, 39, 0, 0, 1, 2, 1, 1};
+ SmartBuffer buf1(sizeof(dev_dsc));
+ buf1.Add(&dev_dsc, sizeof(dev_dsc));
+ EXPECT_EQ(expected, buf1.contents());
+
+ SmartBuffer buf2(sizeof(dev_dsc));
+ buf2.Add(dev_dsc);
+ EXPECT_EQ(expected, buf2.contents());
+}
+
+TEST(Add, AddSmartBuffer) {
+ SmartBuffer buf1(5);
+ SmartBuffer buf2(5);
+ std::vector<uint8_t> expected = {1, 2, 3, 4, 5};
+ buf1.Add(expected.data(), expected.size());
+ buf2.Add(buf1);
+ EXPECT_EQ(buf1.contents(), buf2.contents());
+}
+
+// Test that the proper suffix from the provided SmartBuffer is added.
+TEST(Add, AddSmartBufferSuffix) {
+ SmartBuffer buf1(5);
+ SmartBuffer buf2(5);
+ std::vector<uint8_t> contents = {1, 2, 3, 4, 5};
+ buf1.Add(contents.data(), contents.size());
+
+ std::vector<uint8_t> expected = {3, 4, 5};
+ buf2.Add(buf1, 2);
+ EXPECT_EQ(expected, buf2.contents());
+}
+
+// Test that if the provided start point is 0, then the entire contents of the
+// provided SmartBuffer is added.
+TEST(Add, AddSmartBufferFullSuffix) {
+ SmartBuffer buf1(5);
+ SmartBuffer buf2(5);
+ std::vector<uint8_t> contents = {1, 2, 3, 4, 5};
+ buf1.Add(contents.data(), contents.size());
+
+ buf2.Add(buf1, 0);
+ EXPECT_EQ(contents, buf2.contents());
+}
+
+TEST(Add, AddSmartBufferRange) {
+ SmartBuffer to_copy({1, 2, 3, 4, 5});
+ SmartBuffer to_extend(5);
+ to_extend.Add(to_copy, 1, 3);
+ const std::vector<uint8_t> expected = {2, 3, 4};
+ EXPECT_EQ(to_extend.contents(), expected);
+}
+
+TEST(Erase, EraseSmartBufferRange) {
+ SmartBuffer buf({1, 2, 3, 4, 5});
+ const std::vector<uint8_t> expected = {1, 5};
+ buf.Erase(1, 3);
+ EXPECT_EQ(buf.contents(), expected);
+}
+
+TEST(Resize, Shrink) {
+ SmartBuffer buf(5);
+ std::vector<uint8_t> contents = {1, 2, 3, 4, 5};
+ buf.Add(contents.data(), contents.size());
+ buf.Shrink(3);
+ std::vector<uint8_t> expected = {1, 2, 3};
+ EXPECT_EQ(expected, buf.contents());
+}
+
+} // namespace
diff --git a/usb_printer.cc b/usb_printer.cc
index 457796c..aad88c2 100644
--- a/usb_printer.cc
+++ b/usb_printer.cc
@@ -11,10 +11,10 @@
#include "usbip_constants.h"
#include <algorithm>
+#include <cstdio>
+#include <cstring>
#include <memory>
#include <vector>
-#include <cstring>
-#include <cstdio>
#include <arpa/inet.h>
#include <cups/cups.h>
@@ -113,7 +113,7 @@
void UsbPrinter::HandleUsbData(int sockfd,
const UsbipCmdSubmit& usb_request) const {
- SmartBuffer<uint8_t> smart_buffer =
+ SmartBuffer smart_buffer =
ReceiveBuffer(sockfd, usb_request.transfer_buffer_length);
size_t received = smart_buffer.size();
LOG(INFO) << "Received " << received << " bytes";
@@ -171,7 +171,7 @@
printf("HandleGetStatus %u[%u]\n", control_request.wValue1,
control_request.wValue0);
uint16_t status = 0;
- SmartBuffer<uint8_t> response(sizeof(status));
+ SmartBuffer response(sizeof(status));
response.Add(&status, sizeof(status));
SendUsbControlResponse(sockfd, usb_request, response.data(), response.size());
}
@@ -211,7 +211,7 @@
printf("HandleGetDeviceDescriptor %u[%u]\n", control_request.wValue1,
control_request.wValue0);
- SmartBuffer<uint8_t> response(sizeof(device_descriptor_));
+ SmartBuffer response(sizeof(device_descriptor_));
response.Add(&device_descriptor_, sizeof(device_descriptor_));
SendUsbControlResponse(sockfd, usb_request, response.data(), response.size());
}
@@ -222,7 +222,7 @@
printf("HandleGetConfigurationDescriptor %u[%u]\n", control_request.wValue1,
control_request.wValue0);
- SmartBuffer<uint8_t> response(control_request.wLength);
+ SmartBuffer response(control_request.wLength);
response.Add(&configuration_descriptor_, sizeof(configuration_descriptor_));
if (control_request.wLength == sizeof(configuration_descriptor_)) {
@@ -262,7 +262,7 @@
printf("HandleGetDeviceQualifierDescriptor %u[%u]\n", control_request.wValue1,
control_request.wValue0);
- SmartBuffer<uint8_t> response(sizeof(qualifier_descriptor_));
+ SmartBuffer response(sizeof(qualifier_descriptor_));
response.Add(&qualifier_descriptor_, sizeof(qualifier_descriptor_));
SendUsbControlResponse(sockfd, usb_request, response.data(), response.size());
}
@@ -274,7 +274,7 @@
control_request.wValue0);
int index = control_request.wValue0;
- SmartBuffer<uint8_t> response(strings_[index][0]);
+ SmartBuffer response(strings_[index][0]);
response.Add(strings_[index].data(), strings_[index][0]);
SendUsbControlResponse(sockfd, usb_request, response.data(), response.size());
}
@@ -287,8 +287,7 @@
// Note: For now we only have one configuration set, so we just respond with
// with |configuration_descriptor_.bConfigurationValue|.
- SmartBuffer<uint8_t> response(
- sizeof(configuration_descriptor_.bConfigurationValue));
+ SmartBuffer response(sizeof(configuration_descriptor_.bConfigurationValue));
response.Add(&configuration_descriptor_.bConfigurationValue,
sizeof(configuration_descriptor_.bConfigurationValue));
SendUsbControlResponse(sockfd, usb_request, response.data(), response.size());
@@ -322,7 +321,7 @@
printf("HandleGetDeviceId %u[%u]\n", control_request.wValue1,
control_request.wValue0);
- SmartBuffer<uint8_t> response(ieee_device_id_.size());
+ SmartBuffer response(ieee_device_id_.size());
response.Add(ieee_device_id_.data(), ieee_device_id_.size());
SendUsbControlResponse(sockfd, usb_request, response.data(), response.size());
}
diff --git a/usbip.cc b/usbip.cc
index ed587dd..ee526f6 100644
--- a/usbip.cc
+++ b/usbip.cc
@@ -97,7 +97,7 @@
size_t response_size = sizeof(response);
PackUsbip((int*)&response, response_size);
- SmartBuffer<uint8_t> smart_buffer(response_size);
+ SmartBuffer smart_buffer(response_size);
smart_buffer.Add(&response, response_size);
SendBuffer(sockfd, smart_buffer);
}
@@ -112,7 +112,7 @@
size_t response_size = sizeof(response);
PackUsbip((int*)&response, response_size);
- SmartBuffer<uint8_t> smart_buffer(response_size);
+ SmartBuffer smart_buffer(response_size);
smart_buffer.Add(&response, response_size);
if (data_size > 0) {
smart_buffer.Add(data, data_size);
diff --git a/usbip_constants.h b/usbip_constants.h
index f34cb1b..c6b37aa 100644
--- a/usbip_constants.h
+++ b/usbip_constants.h
@@ -5,10 +5,6 @@
#ifndef __USBIP_CONSTANTS_H__
#define __USBIP_CONSTANTS_H__
-// Type definitions.
-#define byte unsigned char
-#define word unsigned short
-
// USB Decriptor Type Constants.
#define USB_DESCRIPTOR_DEVICE 0x01 // Device Descriptor.
#define USB_DESCRIPTOR_CONFIGURATION 0x02 // Configuration Descriptor.