decoding+transport: Exception-safe Block parsing

Change-Id: I3e83b6ca4c8ca42b8bb1ddc8dc50c52ee366c55c
Refs: #1291
diff --git a/src/encoding/block.cpp b/src/encoding/block.cpp
index eaba9ba..07ec2f0 100644
--- a/src/encoding/block.cpp
+++ b/src/encoding/block.cpp
@@ -59,7 +59,7 @@
 {
   m_value_begin = m_begin;
   m_value_end   = m_end;
-  
+
   m_type = Tlv::readType(m_value_begin, m_value_end);
 
   uint64_t length = Tlv::readVarNumber(m_value_begin, m_value_end);
@@ -93,9 +93,9 @@
 
 Block::Block(std::istream& is)
 {
-  std::istream_iterator<uint8_t> tmp_begin(is);  
+  std::istream_iterator<uint8_t> tmp_begin(is);
   std::istream_iterator<uint8_t> tmp_end;
-  
+
   m_type = Tlv::readType(tmp_begin, tmp_end);
   uint64_t length = Tlv::readVarNumber(tmp_begin, tmp_end);
 
@@ -104,7 +104,7 @@
   OBufferStream os;
   size_t headerLength = Tlv::writeVarNumber(os, m_type);
   headerLength += Tlv::writeVarNumber(os, length);
-  
+
   char* buf = new char[length];
   buf[0] = *tmp_begin;
   is.read(buf+1, length-1);
@@ -113,7 +113,7 @@
     {
       delete [] buf;
       throw Tlv::Error("Not enough data in the buffer to fully parse TLV");
-    } 
+    }
 
   os.write(buf, length);
   delete [] buf;
@@ -132,11 +132,11 @@
 Block::Block(const uint8_t *buffer, size_t maxlength)
 {
   const uint8_t * tmp_begin = buffer;
-  const uint8_t * tmp_end   = buffer + maxlength;  
-  
+  const uint8_t * tmp_end   = buffer + maxlength;
+
   m_type = Tlv::readType(tmp_begin, tmp_end);
   uint64_t length = Tlv::readVarNumber(tmp_begin, tmp_end);
-  
+
   if (length > static_cast<uint64_t>(tmp_end - tmp_begin))
     {
       throw Tlv::Error("Not enough data in the buffer to fully parse TLV");
@@ -155,13 +155,13 @@
 Block::Block(const void *bufferX, size_t maxlength)
 {
   const uint8_t * buffer = reinterpret_cast<const uint8_t*>(bufferX);
-  
+
   const uint8_t * tmp_begin = buffer;
-  const uint8_t * tmp_end   = buffer + maxlength;  
-  
+  const uint8_t * tmp_end   = buffer + maxlength;
+
   m_type = Tlv::readType(tmp_begin, tmp_end);
   uint64_t length = Tlv::readVarNumber(tmp_begin, tmp_end);
-  
+
   if (length > static_cast<uint64_t>(tmp_end - tmp_begin))
     {
       throw Tlv::Error("Not enough data in the buffer to fully parse TLV");
@@ -204,19 +204,75 @@
   m_size = Tlv::sizeOfVarNumber(m_type) + Tlv::sizeOfVarNumber(value_size()) + value_size();
 }
 
+bool
+Block::fromBuffer(const ConstBufferPtr& wire, size_t offset, Block& block)
+{
+  Buffer::const_iterator tempBegin = wire->begin() + offset;
+
+  uint32_t type;
+  bool ok = Tlv::readType(tempBegin, wire->end(), type);
+  if (!ok)
+    return false;
+
+  uint64_t length;
+  ok = Tlv::readVarNumber(tempBegin, wire->end(), length);
+  if (!ok)
+    return false;
+
+  if (length > static_cast<uint64_t>(wire->end() - tempBegin))
+    {
+      return false;
+    }
+
+  block = Block(wire, type,
+                wire->begin() + offset, tempBegin + length,
+                tempBegin, tempBegin + length);
+
+  return true;
+}
+
+bool
+Block::fromBuffer(const uint8_t* buffer, size_t maxSize, Block& block)
+{
+  const uint8_t* tempBegin = buffer;
+  const uint8_t* tempEnd = buffer + maxSize;
+
+  uint32_t type;
+  bool ok = Tlv::readType(tempBegin, tempEnd, type);
+  if (!ok)
+    return false;
+
+  uint64_t length;
+  ok = Tlv::readVarNumber(tempBegin, tempEnd, length);
+  if (!ok)
+    return false;
+
+  if (length > static_cast<uint64_t>(tempEnd - tempBegin))
+    {
+      return false;
+    }
+
+  BufferPtr sharedBuffer = make_shared<Buffer>(buffer, tempBegin + length);
+  block = Block(sharedBuffer, type,
+                sharedBuffer->begin(), sharedBuffer->end(),
+                sharedBuffer->begin() + (tempBegin - buffer), sharedBuffer->end());
+
+  return true;
+}
+
 void
 Block::parse() const
 {
   if (!m_subBlocks.empty() || value_size()==0)
     return;
-  
+
   Buffer::const_iterator begin = value_begin(),
     end = value_end();
 
   while (begin != end)
     {
       Buffer::const_iterator element_begin = begin;
-      
+
       uint32_t type = Tlv::readType(begin, end);
       uint64_t length = Tlv::readVarNumber(begin, end);
 
@@ -226,7 +282,7 @@
           throw Tlv::Error("TLV length exceeds buffer length");
         }
       Buffer::const_iterator element_end = begin + length;
-      
+
       m_subBlocks.push_back(Block(m_buffer,
                                   type,
                                   element_begin, element_end,
@@ -261,7 +317,7 @@
       for (element_const_iterator i = m_subBlocks.begin(); i != m_subBlocks.end(); ++i) {
         valueSize += i->size();
       }
-  
+
       Tlv::writeVarNumber(os, valueSize);
 
       for (element_const_iterator i = m_subBlocks.begin(); i != m_subBlocks.end(); ++i) {
@@ -286,7 +342,7 @@
 
   m_value_begin = m_buffer->begin();
   m_value_end   = m_buffer->end();
-  
+
   Tlv::readType(m_value_begin, m_value_end);
   Tlv::readVarNumber(m_value_begin, m_value_end);
 }
@@ -296,18 +352,18 @@
 {
   if (value_size()==0)
     throw Error("Underlying value buffer is empty");
-  
+
   Buffer::const_iterator begin = value_begin(),
     end = value_end();
 
   Buffer::const_iterator element_begin = begin;
-      
+
   uint32_t type = Tlv::readType(begin, end);
   uint64_t length = Tlv::readVarNumber(begin, end);
 
   if (length != static_cast<uint64_t>(end - begin))
     throw Tlv::Error("TLV length mismatches buffer length");
-      
+
   return Block(m_buffer,
                type,
                element_begin, end,
diff --git a/src/encoding/block.hpp b/src/encoding/block.hpp
index 52ed7e7..a2507b5 100644
--- a/src/encoding/block.hpp
+++ b/src/encoding/block.hpp
@@ -31,8 +31,11 @@
   typedef element_container::const_iterator  element_const_iterator;
 
   /// @brief Error that can be thrown from the block
-  struct Error : public std::runtime_error { Error(const std::string &what) : std::runtime_error(what) {} };
-  
+  struct Error : public std::runtime_error
+  {
+    Error(const std::string& what) : std::runtime_error(what) {}
+  };
+
   /**
    * @brief Default constructor to create an empty Block
    */
@@ -43,11 +46,11 @@
    */
   explicit
   Block(const EncodingBuffer& buffer);
-  
+
   /**
    * @brief A helper version of a constructor to create Block from the raw buffer (type and value-length parsing)
    */
-  Block(const ConstBufferPtr &buffer);
+  Block(const ConstBufferPtr& buffer);
 
   /**
    * @brief Another helper to create block from a buffer, directly specifying boundaries
@@ -55,31 +58,31 @@
    *
    * This version will automatically detect type and position of the value within the block
    */
-  Block(const ConstBufferPtr &buffer,
-        const Buffer::const_iterator &begin, const Buffer::const_iterator &end,
+  Block(const ConstBufferPtr& buffer,
+        const Buffer::const_iterator& begin, const Buffer::const_iterator& end,
         bool verifyLength = true);
-  
+
   /**
    * @brief A helper version of a constructor to create Block from the raw buffer (type and value-length parsing)
    */
-  Block(const uint8_t *buffer, size_t maxlength);
+  Block(const uint8_t* buffer, size_t maxlength);
 
-  Block(const void *buffer, size_t maxlength);
+  Block(const void* buffer, size_t maxlength);
 
   /*
-   * @brief A helper version of a constructor to create Block from the stream. 
+   * @brief A helper version of a constructor to create Block from the stream.
    */
   Block(std::istream& is);
-  
+
   /**
    * @brief Create Block from the wire buffer (no parsing)
    *
    * This version of the constructor does not do any parsing
    */
-  Block(const ConstBufferPtr &wire,
+  Block(const ConstBufferPtr& wire,
         uint32_t type,
-        const Buffer::const_iterator &begin, const Buffer::const_iterator &end,
-        const Buffer::const_iterator &valueBegin, const Buffer::const_iterator &valueEnd);
+        const Buffer::const_iterator& begin, const Buffer::const_iterator& end,
+        const Buffer::const_iterator& valueBegin, const Buffer::const_iterator& valueEnd);
 
   /**
    * @brief Create Block of a specific type with empty wire buffer
@@ -94,7 +97,7 @@
    * to construct wire encoding, one need to prepend the wire buffer with type
    * and value-length VAR-NUMBERs
    */
-  Block(uint32_t type, const ConstBufferPtr &value);
+  Block(uint32_t type, const ConstBufferPtr& value);
 
   /**
    * @brief Create nested Block of a specific type with the specified value
@@ -104,14 +107,34 @@
    * and value-length VAR-NUMBERs
    */
   explicit
-  Block(uint32_t type, const Block &value);
+  Block(uint32_t type, const Block& value);
+
+  /**
+   * @brief Try to construct block from Buffer, referencing data block pointed by wire
+   *
+   * @throws This method never throws an exception
+   *
+   * @returns true if Block successfully created, false if block cannot be created
+   */
+  static bool
+  fromBuffer(const ConstBufferPtr& wire, size_t offset, Block& block);
+
+  /**
+   * @brief Try to construct block from Buffer, referencing data block pointed by wire
+   *
+   * @throws This method never throws an exception
+   *
+   * @returns true if Block successfully created, false if block cannot be created
+   */
+  static bool
+  fromBuffer(const uint8_t* buffer, size_t maxSize, Block& block);
 
   /**
    * @brief Check if the Block is empty
    */
   inline bool
   empty() const;
-  
+
   /**
    * @brief Check if the Block has fully encoded wire
    */
@@ -123,7 +146,7 @@
    */
   inline bool
   hasValue() const;
-  
+
   /**
    * @brief Reset wire buffer of the element
    */
@@ -150,14 +173,14 @@
    */
   void
   encode();
-  
+
   inline uint32_t
   type() const;
 
   /**
    * @brief Get the first subelement of the requested type
    */
-  inline const Block &
+  inline const Block&
   get(uint32_t type) const;
 
   inline element_const_iterator
@@ -171,10 +194,10 @@
 
   inline element_iterator
   erase(element_iterator first, element_iterator last);
-  
+
   inline void
-  push_back(const Block &element);
-  
+  push_back(const Block& element);
+
   inline Buffer::const_iterator
   begin() const;
 
@@ -189,7 +212,7 @@
 
   // inline const uint8_t*
   // buf() const;
-  
+
   inline Buffer::const_iterator
   value_begin() const;
 
@@ -216,7 +239,7 @@
 
   inline size_t
   elements_size() const;
-  
+
   Block
   blockFromValue() const;
 
@@ -224,11 +247,11 @@
   ConstBufferPtr m_buffer;
 
   uint32_t m_type;
-  
+
   Buffer::const_iterator m_begin;
   Buffer::const_iterator m_end;
   uint32_t m_size;
-  
+
   Buffer::const_iterator m_value_begin;
   Buffer::const_iterator m_value_end;
 
@@ -285,7 +308,7 @@
   return m_type;
 }
 
-inline const Block &
+inline const Block&
 Block::get(uint32_t type) const
 {
   for (element_const_iterator i = m_subBlocks.begin ();
@@ -300,7 +323,7 @@
 
   throw Error("(Block::get) Requested a non-existed type [" + boost::lexical_cast<std::string>(type) + "] from Block");
 }
-  
+
 inline Block::element_const_iterator
 Block::find(uint32_t type) const
 {
@@ -409,7 +432,7 @@
 {
   if (!hasValue())
     return 0;
-  
+
   return &*m_value_begin;
 }
 
diff --git a/src/encoding/tlv.hpp b/src/encoding/tlv.hpp
index 8a2b3fc..2ef008c 100644
--- a/src/encoding/tlv.hpp
+++ b/src/encoding/tlv.hpp
@@ -69,7 +69,39 @@
 /**
  * @brief Read VAR-NUMBER in NDN-TLV encoding
  *
- * This call will throw ndn::Tlv::Error (aka std::runtime_error) if number cannot be read
+ * @param [in]  begin  Begin (pointer or iterator) of the buffer
+ * @param [in]  end    End (pointer or iterator) of the buffer
+ * @param [out] number Read number
+ *
+ * @throws This call never throws exception
+ *
+ * @return true if number successfully read from input, false otherwise
+ */
+template<class InputIterator>
+inline bool
+readVarNumber(InputIterator &begin, const InputIterator &end, uint64_t& number);
+
+/**
+ * @brief Read TLV Type
+ *
+ * @param [in]  begin  Begin (pointer or iterator) of the buffer
+ * @param [in]  end    End (pointer or iterator) of the buffer
+ * @param [out] number Read type number
+ *
+ * @throws This call never throws exception
+ *
+ * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
+ * is larger than 2^32-1 (type in this library is implemented as uint32_t)
+ */
+template<class InputIterator>
+inline bool
+readType(InputIterator &begin, const InputIterator &end, uint32_t& type);
+
+
+/**
+ * @brief Read VAR-NUMBER in NDN-TLV encoding
+ *
+ * @throws This call will throw ndn::Tlv::Error (aka std::runtime_error) if number cannot be read
  *
  * Note that after call finished, begin will point to the first byte after the read VAR-NUMBER
  */
@@ -80,6 +112,8 @@
 /**
  * @brief Read TLV Type
  *
+ * @throws This call will throw ndn::Tlv::Error (aka std::runtime_error) if number cannot be read
+ *
  * This call is largely equivalent to tlv::readVarNumber, but exception will be thrown if type
  * is larger than 2^32-1 (type in this library is implemented as uint32_t)
  */
@@ -136,12 +170,72 @@
 /////////////////////////////////////////////////////////////////////////////////
 
 template<class InputIterator>
+inline bool
+readVarNumber(InputIterator &begin, const InputIterator &end, uint64_t& number)
+{
+  if (begin == end)
+    return false;
+
+  uint8_t value = *begin;
+  ++begin;
+  if (value < 253)
+    {
+      number = value;
+    }
+  else if (value == 253)
+    {
+      if (end - begin < 2)
+        return false;
+
+      uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin); // kind of dangerous... but should be efficient
+      begin += 2;
+      number = be16toh(value);
+    }
+  else if (value == 254)
+    {
+      if (end - begin < 4)
+        return false;
+
+      uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin); // kind of dangerous... but should be efficient
+      begin += 4;
+      number = be32toh(value);
+    }
+  else // if (value == 255)
+    {
+      if (end - begin < 8)
+        return false;
+
+      uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
+      begin += 8;
+
+      number = be64toh(value);
+    }
+
+  return true;
+}
+
+template<class InputIterator>
+inline bool
+readType(InputIterator &begin, const InputIterator &end, uint32_t& type)
+{
+  uint64_t number;
+  bool ok = readVarNumber(begin, end, number);
+  if (number > std::numeric_limits<uint32_t>::max())
+    {
+      return false;
+    }
+
+  type = static_cast<uint64_t> (number);
+  return true;
+}
+
+template<class InputIterator>
 inline uint64_t
 readVarNumber(InputIterator &begin, const InputIterator &end)
 {
   if (begin == end)
     throw Error("Empty buffer during TLV processing");
-  
+
   uint8_t value = *begin;
   ++begin;
   if (value < 253)
@@ -152,7 +246,7 @@
     {
       if (end - begin < 2)
         throw Error("Insufficient data during TLV processing");
-      
+
       uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin); // kind of dangerous... but should be efficient
       begin += 2;
       return be16toh(value);
@@ -161,7 +255,7 @@
     {
       if (end - begin < 4)
         throw Error("Insufficient data during TLV processing");
-      
+
       uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin); // kind of dangerous... but should be efficient
       begin += 4;
       return be32toh(value);
@@ -170,7 +264,7 @@
     {
       if (end - begin < 8)
         throw Error("Insufficient data during TLV processing");
-      
+
       uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
       begin += 8;
 
@@ -180,12 +274,12 @@
 
 template<>
 inline uint64_t
-readVarNumber<std::istream_iterator<uint8_t> >(std::istream_iterator<uint8_t> &begin, 
+readVarNumber<std::istream_iterator<uint8_t> >(std::istream_iterator<uint8_t> &begin,
                                                const std::istream_iterator<uint8_t> &end)
 {
   if (begin == end)
     throw Error("Empty buffer during TLV processing");
-  
+
   uint8_t value = *begin;
   ++begin;
   if (value < 253)
@@ -196,7 +290,7 @@
     {
       uint8_t buffer[2];
       int count = 0;
-      
+
       while(begin != end && count < 2){
         buffer[count] = *begin;
         begin++;
@@ -205,15 +299,15 @@
 
       if (count < 2)
         throw Error("Insufficient data during TLV processing");
-      
-      uint16_t value = *reinterpret_cast<const uint16_t*>(buffer); 
+
+      uint16_t value = *reinterpret_cast<const uint16_t*>(buffer);
       return be16toh(value);
     }
   else if (value == 254)
     {
       uint8_t buffer[4];
       int count = 0;
-      
+
       while(begin != end && count < 4){
         buffer[count] = *begin;
         begin++;
@@ -222,7 +316,7 @@
 
       if (count < 4)
         throw Error("Insufficient data during TLV processing");
-      
+
       uint32_t value = *reinterpret_cast<const uint32_t*>(buffer);
       return be32toh(value);
     }
@@ -230,7 +324,7 @@
     {
       uint8_t buffer[8];
       int count = 0;
-      
+
       while(begin != end && count < 8){
         buffer[count] = *begin;
         begin++;
@@ -239,7 +333,7 @@
 
       if (count < 8)
         throw Error("Insufficient data during TLV processing");
-      
+
       uint64_t value = *reinterpret_cast<const uint64_t*>(buffer);
       return be64toh(value);
     }
@@ -311,7 +405,7 @@
     {
       if (end - begin < 1)
         throw Error("Insufficient data during TLV processing");
-      
+
       uint8_t value = *begin;
       begin++;
       return value;
@@ -320,7 +414,7 @@
     {
       if (end - begin < 2)
         throw Error("Insufficient data during TLV processing");
-      
+
       uint16_t value = *reinterpret_cast<const uint16_t*>(&*begin); // kind of dangerous... but should be efficient
       begin += 2;
       return be16toh(value);
@@ -329,7 +423,7 @@
     {
       if (end - begin < 4)
         throw Error("Insufficient data during TLV processing");
-      
+
       uint32_t value = *reinterpret_cast<const uint32_t*>(&*begin); // kind of dangerous... but should be efficient
       begin += 4;
       return be32toh(value);
@@ -338,7 +432,7 @@
     {
       if (end - begin < 8)
         throw Error("Insufficient data during TLV processing");
-      
+
       uint64_t value = *reinterpret_cast<const uint64_t*>(&*begin);
       begin += 8;
       return be64toh(value);
@@ -349,8 +443,8 @@
 
 template<>
 inline uint64_t
-readNonNegativeInteger<std::istream_iterator<uint8_t> >(size_t size, 
-                                                        std::istream_iterator<uint8_t> &begin, 
+readNonNegativeInteger<std::istream_iterator<uint8_t> >(size_t size,
+                                                        std::istream_iterator<uint8_t> &begin,
                                                         const std::istream_iterator<uint8_t> &end)
 {
   switch (size) {
@@ -358,7 +452,7 @@
     {
       if(begin == end)
         throw Error("Insufficient data during TLV processing");
-      
+
       uint8_t value = *begin;
       begin++;
       return value;
@@ -367,16 +461,16 @@
     {
       uint8_t buffer[2];
       int count = 0;
-      
+
       while(begin != end && count < 2){
         buffer[count] = *begin;
         begin++;
         count++;
       }
-      
+
       if (count < 2)
         throw Error("Insufficient data during TLV processing");
-      
+
       uint16_t value = *reinterpret_cast<const uint16_t*>(buffer);
       return be16toh(value);
     }
@@ -384,7 +478,7 @@
     {
       uint8_t buffer[4];
       int count = 0;
-      
+
       while(begin != end && count < 4){
         buffer[count] = *begin;
         begin++;
@@ -393,7 +487,7 @@
 
       if (count < 4)
         throw Error("Insufficient data during TLV processing");
-      
+
       uint32_t value = *reinterpret_cast<const uint32_t*>(buffer);
       return be32toh(value);
     }
@@ -401,7 +495,7 @@
     {
       uint8_t buffer[8];
       int count = 0;
-      
+
       while(begin != end && count < 8){
         buffer[count] = *begin;
         begin++;
@@ -410,7 +504,7 @@
 
       if (count < 8)
         throw Error("Insufficient data during TLV processing");
-      
+
       uint64_t value = *reinterpret_cast<const uint64_t*>(buffer);
       return be64toh(value);
     }
diff --git a/src/transport/stream-transport.hpp b/src/transport/stream-transport.hpp
index 8562d88..713d740 100644
--- a/src/transport/stream-transport.hpp
+++ b/src/transport/stream-transport.hpp
@@ -24,12 +24,12 @@
   StreamTransportImpl(base_transport& transport, boost::asio::io_service& ioService)
     : m_transport(transport)
     , m_socket(ioService)
-    , m_partialDataSize(0)
+    , m_inputBufferSize(0)
     , m_connectionInProgress(false)
     , m_connectTimer(ioService)
   {
   }
-  
+
   void
   connectHandler(const boost::system::error_code& error)
   {
@@ -55,7 +55,7 @@
             m_socket.async_send(buffer,
                                 bind(&impl::handle_async_send, this, _1, i->first, i->second));
           }
-        
+
         m_sendQueue.clear();
         m_sendPairQueue.clear();
       }
@@ -76,6 +76,7 @@
 
     m_connectionInProgress = false;
     m_transport.m_isConnected = false;
+    m_transport.m_isExpectingData = false;
     m_socket.close();
     throw Transport::Error(error, "error while connecting to the forwarder");
   }
@@ -96,8 +97,8 @@
                              bind(&impl::connectHandler, this, _1));
     }
   }
-  
-  void 
+
+  void
   close()
   {
     m_connectTimer.cancel();
@@ -124,7 +125,7 @@
     if (!m_transport.m_isExpectingData)
       {
         m_transport.m_isExpectingData = true;
-        m_partialDataSize = 0;
+        m_inputBufferSize = 0;
         m_socket.async_receive(boost::asio::buffer(m_inputBuffer, MAX_LENGTH), 0,
                                bind(&impl::handle_async_receive, this, _1, _2));
       }
@@ -153,113 +154,75 @@
         buffers.reserve(2);
         buffers.push_back(boost::asio::buffer(header.wire(),  header.size()));
         buffers.push_back(boost::asio::buffer(payload.wire(), payload.size()));
-                          
+
         m_socket.async_send(buffers,
                             bind(&impl::handle_async_send, this, _1, header, payload));
       }
   }
-  
-  inline void
+
+  inline bool
   processAll(uint8_t* buffer, size_t& offset, size_t availableSize)
   {
+    Block element;
     while(offset < availableSize)
       {
-        Block element(buffer + offset, availableSize - offset);
-        m_transport.receive(element);
+        bool ok = Block::fromBuffer(buffer + offset, availableSize - offset, element);
+        if (!ok)
+          return false;
 
+        m_transport.receive(element);
         offset += element.size();
       }
+    return true;
   }
-  
+
   void
   handle_async_receive(const boost::system::error_code& error, std::size_t bytes_recvd)
   {
-    /// @todo The socket is not datagram, so need to have internal buffer to handle partial data reception
-
     if (error)
       {
         if (error == boost::system::errc::operation_canceled) {
           // async receive has been explicitly cancelled (e.g., socket close)
           return;
         }
-        
+
         m_socket.close(); // closing at this point may not be that necessary
         m_transport.m_isConnected = true;
         throw Transport::Error(error, "error while receiving data from socket");
       }
-    
-    if (!error && bytes_recvd > 0)
+
+    m_inputBufferSize += bytes_recvd;
+    // do magic
+
+    std::size_t offset = 0;
+    bool ok = processAll(m_inputBuffer, offset, m_inputBufferSize);
+    if (!ok && m_inputBufferSize == MAX_LENGTH && offset == 0)
       {
-        // m_inputBuffer has bytes_recvd received bytes of data
-        if (m_partialDataSize > 0)
+        // very bad... should close connection
+        m_socket.close();
+        m_transport.m_isConnected = false;
+        m_transport.m_isExpectingData = false;
+        throw Transport::Error(boost::system::error_code(),
+                               "input buffer full, but a valid TLV cannot be decoded");
+      }
+
+    if (offset > 0)
+      {
+        if (offset != m_inputBufferSize)
           {
-            size_t newDataSize = std::min(bytes_recvd, MAX_LENGTH-m_partialDataSize);
-            std::copy(m_inputBuffer, m_inputBuffer + newDataSize, m_partialData + m_partialDataSize);
-
-            m_partialDataSize += newDataSize;
-              
-            size_t offset = 0;
-            try
-              {
-                processAll(m_partialData, offset, m_partialDataSize);
-
-                // no exceptions => processed the whole thing
-                if (bytes_recvd - newDataSize > 0)
-                  {
-                    // there is a little bit more data available
-                        
-                    offset = 0;
-                    m_partialDataSize = bytes_recvd - newDataSize;
-                    std::copy(m_inputBuffer + newDataSize, m_inputBuffer + newDataSize + m_partialDataSize, m_partialData);
-
-                    processAll(m_partialData, offset, m_partialDataSize);
-
-                    // no exceptions => processed the whole thing
-                    m_partialDataSize = 0;
-                  }
-                else
-                  {
-                    // done processing
-                    m_partialDataSize = 0;
-                  }
-              }
-            catch(Tlv::Error &)
-              {
-                if (offset > 0)
-                  {
-                    m_partialDataSize -= offset;
-                    std::copy(m_partialData + offset, m_partialData + offset + m_partialDataSize, m_partialData);
-                  }
-                else if (offset == 0 && m_partialDataSize == MAX_LENGTH)
-                  {
-                    // very bad... should close connection
-                    m_socket.close();
-                    m_transport.m_isConnected = true;
-                    throw Transport::Error(boost::system::error_code(),
-                                           "input buffer full, but a valid TLV cannot be decoded");
-                  }
-              }
+            std::copy(m_inputBuffer + offset, m_inputBuffer + m_inputBufferSize,
+                      m_inputBuffer);
+            m_inputBufferSize -= offset;
           }
         else
           {
-            size_t offset = 0;
-            try
-              {
-                processAll(m_inputBuffer, offset, bytes_recvd);
-              }
-            catch(Tlv::Error &error)
-              {
-                if (offset > 0)
-                  {
-                    m_partialDataSize = bytes_recvd - offset;
-                    std::copy(m_inputBuffer + offset, m_inputBuffer + offset + m_partialDataSize, m_partialData);
-                  }
-              }
+            m_inputBufferSize = 0;
           }
       }
 
-    m_socket.async_receive(boost::asio::buffer(m_inputBuffer, MAX_LENGTH), 0,
-                          bind(&impl::handle_async_receive, this, _1, _2));
+    m_socket.async_receive(boost::asio::buffer(m_inputBuffer + m_inputBufferSize,
+                                               MAX_LENGTH - m_inputBufferSize), 0,
+                           bind(&impl::handle_async_receive, this, _1, _2));
   }
 
   void
@@ -277,12 +240,10 @@
 
 protected:
   base_transport& m_transport;
-  
+
   typename protocol::socket m_socket;
   uint8_t m_inputBuffer[MAX_LENGTH];
-
-  uint8_t m_partialData[MAX_LENGTH];
-  size_t m_partialDataSize;
+  size_t m_inputBufferSize;
 
   std::list< Block > m_sendQueue;
   std::list< std::pair<Block, Block> > m_sendPairQueue;
@@ -304,7 +265,7 @@
     : StreamTransportImpl<base_transport, protocol>(transport, ioService)
   {
   }
-  
+
   void
   resolveHandler(const boost::system::error_code& error,
                  typename protocol::resolver::iterator endpoint,
@@ -314,15 +275,16 @@
       {
         if (error == boost::system::errc::operation_canceled)
           return;
-        
+
         throw Transport::Error(error, "Error during resolution of host or port");
       }
-    
+
     typename protocol::resolver::iterator end;
     if (endpoint == end)
       {
         this->m_connectionInProgress = false;
         this->m_transport.m_isConnected = false;
+        this->m_transport.m_isExpectingData = false;
         this->m_socket.close();
         throw Transport::Error(error, "Unable to resolve because host or port");
       }
@@ -330,7 +292,7 @@
     this->m_socket.async_connect(*endpoint,
                                  bind(&impl::connectHandler, this, _1));
   }
-  
+
   void
   connect(const typename protocol::resolver::query& query)
   {
diff --git a/tests/test-block.cpp b/tests/test-block.cpp
index ea0c9b4..be2d2a6 100644
--- a/tests/test-block.cpp
+++ b/tests/test-block.cpp
@@ -12,28 +12,28 @@
 
 BOOST_AUTO_TEST_SUITE(TestBlock)
 
-BOOST_AUTO_TEST_CASE (Basic)
+BOOST_AUTO_TEST_CASE(Basic)
 {
   EncodingBuffer buffer;
   EncodingEstimator estimator;
   size_t s1, s2;
 
   // VarNumber checks
-  
+
   s1 = buffer.prependVarNumber(252);
   s2 = estimator.prependVarNumber(252);
   BOOST_CHECK_EQUAL(buffer.size(), 1);
   BOOST_CHECK_EQUAL(s1, 1);
   BOOST_CHECK_EQUAL(s2, 1);
   buffer = EncodingBuffer();
-  
+
   s1 = buffer.prependVarNumber(253);
   s2 = estimator.prependVarNumber(253);
   BOOST_CHECK_EQUAL(buffer.size(), 3);
   BOOST_CHECK_EQUAL(s1, 3);
   BOOST_CHECK_EQUAL(s2, 3);
   buffer = EncodingBuffer();
-  
+
   s1 = buffer.prependVarNumber(255);
   s2 = estimator.prependVarNumber(255);
   BOOST_CHECK_EQUAL(buffer.size(), 3);
@@ -54,7 +54,7 @@
   BOOST_CHECK_EQUAL(s1, 5);
   BOOST_CHECK_EQUAL(s2, 5);
   buffer = EncodingBuffer();
-  
+
   s1 = buffer.prependVarNumber(4294967295);
   s2 = estimator.prependVarNumber(4294967295);
   BOOST_CHECK_EQUAL(buffer.size(), 5);
@@ -70,21 +70,21 @@
   buffer = EncodingBuffer();
 
   // nonNegativeInteger checks
-  
+
   s1 = buffer.prependNonNegativeInteger(252);
   s2 = estimator.prependNonNegativeInteger(252);
   BOOST_CHECK_EQUAL(buffer.size(), 1);
   BOOST_CHECK_EQUAL(s1, 1);
   BOOST_CHECK_EQUAL(s2, 1);
   buffer = EncodingBuffer();
-  
+
   s1 = buffer.prependNonNegativeInteger(255);
   s2 = estimator.prependNonNegativeInteger(255);
   BOOST_CHECK_EQUAL(buffer.size(), 1);
   BOOST_CHECK_EQUAL(s1, 1);
   BOOST_CHECK_EQUAL(s2, 1);
   buffer = EncodingBuffer();
-  
+
   s1 = buffer.prependNonNegativeInteger(256);
   s2 = estimator.prependNonNegativeInteger(256);
   BOOST_CHECK_EQUAL(buffer.size(), 2);
@@ -121,7 +121,7 @@
   buffer = EncodingBuffer();
 }
 
-BOOST_AUTO_TEST_CASE (EncodingBufferToBlock)
+BOOST_AUTO_TEST_CASE(EncodingBufferToBlock)
 {
   uint8_t value[4];
 
@@ -140,11 +140,11 @@
   BOOST_CHECK_EQUAL(block.value_size(), sizeof(value));
 }
 
-BOOST_AUTO_TEST_CASE (BlockToBuffer)
+BOOST_AUTO_TEST_CASE(BlockToBuffer)
 {
   shared_ptr<Buffer> buf = make_shared<Buffer>(10);
   for (int i = 0; i < 10; i++) (*buf)[i] = i;
-  
+
   Block block(0xab, buf);
   block.encode();
 
@@ -163,6 +163,55 @@
   BOOST_CHECK_EQUAL(buffer.capacity(), 10);
 }
 
+BOOST_AUTO_TEST_CASE(FromBuffer)
+{
+  const uint8_t TEST_BUFFER[] = {0x00, 0x01, 0xfa, // ok
+                                 0x01, 0x01, 0xfb, // ok
+                                 0x03, 0x02, 0xff}; // not ok
+  BufferPtr buffer(new Buffer(TEST_BUFFER, sizeof(TEST_BUFFER)));
+
+  // using BufferPtr (avoids memory copy)
+  size_t offset = 0;
+  Block testBlock;
+  BOOST_CHECK(Block::fromBuffer(buffer, offset, testBlock));
+  BOOST_CHECK_EQUAL(testBlock.type(), 0);
+  BOOST_CHECK_EQUAL(testBlock.size(), 3);
+  BOOST_CHECK_EQUAL(testBlock.value_size(), 1);
+  BOOST_CHECK_EQUAL(*testBlock.wire(),  0x00);
+  BOOST_CHECK_EQUAL(*testBlock.value(), 0xfa);
+  offset += testBlock.size();
+
+  BOOST_CHECK(Block::fromBuffer(buffer, offset, testBlock));
+  BOOST_CHECK_EQUAL(testBlock.type(), 1);
+  BOOST_CHECK_EQUAL(testBlock.size(), 3);
+  BOOST_CHECK_EQUAL(testBlock.value_size(), 1);
+  BOOST_CHECK_EQUAL(*testBlock.wire(),  0x01);
+  BOOST_CHECK_EQUAL(*testBlock.value(), 0xfb);
+  offset += testBlock.size();
+
+  BOOST_CHECK(!Block::fromBuffer(buffer, offset, testBlock));
+
+  // just buffer, copies memory
+  offset = 0;
+  BOOST_CHECK(Block::fromBuffer(TEST_BUFFER + offset, sizeof(TEST_BUFFER) - offset, testBlock));
+  BOOST_CHECK_EQUAL(testBlock.type(), 0);
+  BOOST_CHECK_EQUAL(testBlock.size(), 3);
+  BOOST_CHECK_EQUAL(testBlock.value_size(), 1);
+  BOOST_CHECK_EQUAL(*testBlock.wire(),  0x00);
+  BOOST_CHECK_EQUAL(*testBlock.value(), 0xfa);
+  offset += testBlock.size();
+
+  BOOST_CHECK(Block::fromBuffer(TEST_BUFFER + offset, sizeof(TEST_BUFFER) - offset, testBlock));
+  BOOST_CHECK_EQUAL(testBlock.type(), 1);
+  BOOST_CHECK_EQUAL(testBlock.size(), 3);
+  BOOST_CHECK_EQUAL(testBlock.value_size(), 1);
+  BOOST_CHECK_EQUAL(*testBlock.wire(),  0x01);
+  BOOST_CHECK_EQUAL(*testBlock.value(), 0xfb);
+  offset += testBlock.size();
+
+  BOOST_CHECK(!Block::fromBuffer(TEST_BUFFER + offset, sizeof(TEST_BUFFER) - offset, testBlock));
+}
+
 BOOST_AUTO_TEST_SUITE_END()
 
 } // namespace ndn