Build the mbuf directly instead of copying in web_proxy

No sense doing a malloc followed by a memcpy for each packet.  Instead,
we know how big the message will be, so allocate that much memory and
build directly into it.

Change-Id: Ie2361ced5403ff481dd10b30e8d9f106071c506b
diff --git a/aos/network/web_proxy.cc b/aos/network/web_proxy.cc
index 6147e46..b53feab 100644
--- a/aos/network/web_proxy.cc
+++ b/aos/network/web_proxy.cc
@@ -199,17 +199,25 @@
             << "packets";
     for (int packet_index = 0;
          packet_index < GetPacketCount(fetcher_->context()); ++packet_index) {
-      flatbuffers::FlatBufferBuilder fbb;
-      flatbuffers::Offset<MessageHeader> message_offset =
-          PackMessage(&fbb, fetcher_->context(), channel_index_, packet_index);
-      fbb.Finish(message_offset);
+      // Pack directly into the mbuffer.  This is admittedly a bit painful.
+      const size_t packet_size =
+          PackedMessageSize(fetcher_->context(), packet_index);
+      struct mbuf *mbuffer = mbuf_alloc(packet_size);
 
-      const flatbuffers::DetachedBuffer buffer = fbb.Release();
+      {
+        // Wrap a pre-allocated builder around the mbuffer.
+        PreallocatedAllocator allocator(mbuf_buf(mbuffer), packet_size);
+        flatbuffers::FlatBufferBuilder fbb(packet_size, &allocator);
+        flatbuffers::Offset<MessageHeader> message_offset = PackMessage(
+            &fbb, fetcher_->context(), channel_index_, packet_index);
+        fbb.Finish(message_offset);
 
-
-      struct mbuf *mbuffer = mbuf_alloc(buffer.size());
-      mbuf_write_mem(mbuffer, buffer.data(), buffer.size());
-      mbuf_set_pos(mbuffer, 0);
+        // Now, the flatbuffer is built from the back to the front.  So any
+        // extra memory will be at the front.  Setup the end and start pointers
+        // on the mbuf.
+        mbuf_set_end(mbuffer, packet_size);
+        mbuf_set_pos(mbuffer, packet_size - fbb.GetSize());
+      }
 
       message.data.emplace_back(
           std::shared_ptr<struct mbuf>(mbuffer, mem_deref));
diff --git a/aos/network/web_proxy_utils.cc b/aos/network/web_proxy_utils.cc
index deb4a38..d6148d4 100644
--- a/aos/network/web_proxy_utils.cc
+++ b/aos/network/web_proxy_utils.cc
@@ -9,6 +9,10 @@
 // the middle which seems to work.
 constexpr size_t kPacketSize = 125000;
 
+// Max header size we have seen is 72 bytes, followed by 48 bytes of scratch
+// space.
+constexpr size_t kMaxHeaderSize = 72 + 48;
+
 int GetPacketCountFromSize(const int packet_size) {
   return packet_size / kPacketSize + 1;
 }
@@ -35,6 +39,19 @@
   return GetPacketCountFromSize(context.size);
 }
 
+size_t PackedMessageSize(const Context &context, int packet_index) {
+  // Make sure the final size is aligned because flatbuffers will align it up
+  // otherwise.
+  constexpr size_t kAlignment = 8;
+  if (kPacketSize * (packet_index + 1) < context.size) {
+    return (kPacketSize + kMaxHeaderSize + kAlignment - 1) & ~(kAlignment - 1);
+  } else {
+    const int prefix_size = kPacketSize * packet_index;
+    return (context.size - prefix_size + kMaxHeaderSize + kAlignment - 1) &
+           ~(kAlignment - 1);
+  }
+}
+
 flatbuffers::Offset<MessageHeader> PackMessage(
     flatbuffers::FlatBufferBuilder *fbb, const Context &context,
     int channel_index, int packet_index) {
diff --git a/aos/network/web_proxy_utils.h b/aos/network/web_proxy_utils.h
index cfed19d..19b496d 100644
--- a/aos/network/web_proxy_utils.h
+++ b/aos/network/web_proxy_utils.h
@@ -14,6 +14,10 @@
     flatbuffers::FlatBufferBuilder *fbb, const Context &context,
     int channel_index, int packet_index);
 
+// Returns the size that the overall packed message packed by PackMessage will
+// be for the provided packet index.
+size_t PackedMessageSize(const Context &context, int packet_index);
+
 // Packs the provided raw data into a series of MessageHeader's of the
 // appropriate length.
 std::vector<FlatbufferDetachedBuffer<MessageHeader>> PackBuffer(