firmware: tie implementation of session into write

To demonstrate how session will work, implement the write command.
Everything isn't wired up with open(), therefore this code itself will
only work in isolation.

This requires wiring up the open command to verify write will use the
handler we specify.

Change-Id: Icf5cfad4ddb531bc271642e24d505cbb9abf8f22
Signed-off-by: Patrick Venture <venture@google.com>
diff --git a/firmware_handler.cpp b/firmware_handler.cpp
index b51849d..2ee4155 100644
--- a/firmware_handler.cpp
+++ b/firmware_handler.cpp
@@ -4,6 +4,7 @@
 
 #include <algorithm>
 #include <cstdint>
+#include <cstring>
 #include <memory>
 #include <string>
 #include <vector>
@@ -36,7 +37,11 @@
     {
         blobs.push_back(item.blobName);
     }
-    blobs.push_back(hashBlobID);
+
+    if (0 == std::count(blobs.begin(), blobs.end(), hashBlobID))
+    {
+        return nullptr;
+    }
 
     std::uint16_t bitmask = 0;
     for (const auto& item : transports)
@@ -169,7 +174,8 @@
      */
 
     /* Check the flags for the transport mechanism: if none match we don't
-     * support what they request. */
+     * support what they request.
+     */
     if ((flags & bitmask) == 0)
     {
         return false;
@@ -179,15 +185,34 @@
     if (path == activeImageBlobID)
     {
         /* 2a) are they opening the active image? this can only happen if they
-         * already started one (due to canHandleBlob's behavior). */
+         * already started one (due to canHandleBlob's behavior).
+         */
     }
     else if (path == activeHashBlobID)
     {
         /* 2b) are they opening the active hash? this can only happen if they
-         * already started one (due to canHandleBlob's behavior). */
+         * already started one (due to canHandleBlob's behavior).
+         */
     }
-    else if (path == hashBlobID)
+
+    /* How are they expecting to copy this data? */
+    auto d = std::find_if(
+        transports.begin(), transports.end(),
+        [&flags](const auto& iter) { return (iter.bitmask & flags); });
+    if (d == transports.end())
     {
+        return false;
+    }
+
+    /* We found the transport handler they requested, no surprise since
+     * above we verify they selected at least one we wanted.
+     */
+    Session* curr;
+
+    if (path == hashBlobID)
+    {
+        curr = &activeHash;
+
         /* 2c) are they opening the /flash/hash ? (to start the process) */
 
         /* Add active hash blob_id to canHandle list. */
@@ -195,49 +220,38 @@
     }
     else
     {
-        /* How are they expecting to copy this data? */
-        auto d = std::find_if(
-            transports.begin(), transports.end(),
-            [&flags](const auto& iter) { return (iter.bitmask & flags); });
-        if (d == transports.end())
-        {
-            return false;
-        }
-
-        /* We found the transport handler they requested, no surprise since
-         * above we verify they selected at least one we wanted.
-         */
-
-        /* 2d) are they opening the /flash/tarball ? (to start the UBI process)
-         */
-        /* 2e) are they opening the /flash/image ? (to start the process) */
-        /* 2...) are they opening the /flash/... ? (to start the process) */
-
-        auto h = std::find_if(
-            handlers.begin(), handlers.end(),
-            [&path](const auto& iter) { return (iter.blobName == path); });
-        if (h == handlers.end())
-        {
-            return false;
-        }
-
-        /* Ok, so we found a handler that matched, so call open() */
-        if (!h->handler->open(path))
-        {
-            return false;
-        }
-
-        /* open() succeeded. */
-
-        /* TODO: Actually handle storing this information. */
+        curr = &activeImage;
 
         /* add active image blob_id to canHandle list. */
         blobIDs.push_back(activeImageBlobID);
-
-        return true;
     }
 
-    return false;
+    /* 2d) are they opening the /flash/tarball ? (to start the UBI process)
+     */
+    /* 2e) are they opening the /flash/image ? (to start the process) */
+    /* 2...) are they opening the /flash/... ? (to start the process) */
+
+    auto h = std::find_if(
+        handlers.begin(), handlers.end(),
+        [&path](const auto& iter) { return (iter.blobName == path); });
+    if (h == handlers.end())
+    {
+        return false;
+    }
+
+    /* Ok, so we found a handler that matched, so call open() */
+    if (!h->handler->open(path))
+    {
+        return false;
+    }
+
+    curr->flags = flags;
+    curr->dataHandler = d->handler;
+    curr->imageHandler = h->handler;
+
+    lookup[session] = curr;
+
+    return true;
 }
 
 std::vector<uint8_t> FirmwareBlobHandler::read(uint16_t session,
@@ -251,15 +265,45 @@
     return {};
 }
 
+/**
+ * The write command really just grabs the data from wherever it is and sends it
+ * to the image handler.  It's the image handler's responsibility to deal with
+ * the data provided.
+ */
 bool FirmwareBlobHandler::write(uint16_t session, uint32_t offset,
                                 const std::vector<uint8_t>& data)
 {
-    /*
-     * This will do whatever behavior is expected by mechanism - likely will
-     * just call the specific write handler.
-     */
-    return false;
+    auto item = lookup.find(session);
+    if (item == lookup.end())
+    {
+        return false;
+    }
+
+    std::vector<std::uint8_t> bytes;
+
+    if (item->second->flags & FirmwareUpdateFlags::ipmi)
+    {
+        bytes = data;
+    }
+    else
+    {
+        /* little endian required per design, and so on, but TODO: do endianness
+         * with boost.
+         */
+        struct ExtChunkHdr header;
+
+        if (data.size() != sizeof(header))
+        {
+            return false;
+        }
+
+        std::memcpy(&header, data.data(), data.size());
+        bytes = item->second->dataHandler->copyFrom(header.length);
+    }
+
+    return item->second->imageHandler->write(offset, bytes);
 }
+
 bool FirmwareBlobHandler::writeMeta(uint16_t session, uint32_t offset,
                                     const std::vector<uint8_t>& data)
 {