stream-face: invoke shutdown() before closing the socket.

As recommended by boost::asio documentation.
Also refactor the shutdown logic into its own method.

Change-Id: I033de350a9cb659439034f7b5bb36031cda87a25
diff --git a/daemon/face/stream-face.hpp b/daemon/face/stream-face.hpp
index a659373..9573813 100644
--- a/daemon/face/stream-face.hpp
+++ b/daemon/face/stream-face.hpp
@@ -46,10 +46,13 @@
 
   void
   keepFaceAliveUntilAllHandlersExecuted(const shared_ptr<Face>& face);
-  
+
+  void
+  closeSocket();
+
 protected:
   shared_ptr<typename protocol::socket> m_socket;
-  
+
 private:
   uint8_t m_inputBuffer[MAX_NDN_PACKET_SIZE];
   std::size_t m_inputBufferSize;
@@ -109,17 +112,8 @@
   NFD_LOG_INFO("[id:" << this->getId()
                << ",endpoint:" << m_socket->local_endpoint()
                << "] Close connection");
-  
-  
-  boost::asio::io_service& io = m_socket->get_io_service();
-  m_socket->close();
-  // after this, handleSend/handleReceive will be called with set error code
 
-  // ensure that if that Face object is alive at least until all pending
-  // methods are dispatched
-  io.post(bind(&StreamFace<T>::keepFaceAliveUntilAllHandlersExecuted,
-               this, this->shared_from_this()));
-
+  closeSocket();
   onFail("Close connection");
 }
 
@@ -152,14 +146,8 @@
                      << error.category().message(error.value()));
       }
 
-    boost::asio::io_service& io = m_socket->get_io_service();
-    m_socket->close();
-    
-    // ensure that if that Face object is alive at least until all pending
-    // methods are dispatched
-    io.post(bind(&StreamFace<T>::keepFaceAliveUntilAllHandlersExecuted,
-                 this, this->shared_from_this()));
-    
+    closeSocket();
+
     if (error == boost::asio::error::eof)
       {
         onFail("Connection closed");
@@ -207,14 +195,8 @@
                      << "] Receive operation failed: "
                      << error.category().message(error.value()));
       }
-    
-    boost::asio::io_service& io = m_socket->get_io_service();
-    m_socket->close();
-    
-    // ensure that if that Face object is alive at least until all pending
-    // methods are dispatched
-    io.post(bind(&StreamFace<T>::keepFaceAliveUntilAllHandlersExecuted,
-                 this, this->shared_from_this()));
+
+    closeSocket();
 
     if (error == boost::asio::error::eof)
       {
@@ -281,15 +263,8 @@
                      << ",endpoint:" << m_socket->local_endpoint()
                      << "] Received input is invalid or too large to process, "
                      << "closing down the face");
-        
-        boost::asio::io_service& io = m_socket->get_io_service();
-        m_socket->close();
-    
-        // ensure that if that Face object is alive at least until all pending
-        // methods are dispatched
-        io.post(bind(&StreamFace<T>::keepFaceAliveUntilAllHandlersExecuted,
-                     this, this->shared_from_this()));
-        
+
+        closeSocket();
         onFail("Received input is invalid or too large to process, closing down the face");
         return;
       }
@@ -320,6 +295,23 @@
 {
 }
 
+template <class T>
+inline void
+StreamFace<T>::closeSocket()
+{
+  boost::asio::io_service& io = m_socket->get_io_service();
+
+  // use the non-throwing variants and ignore errors, if any
+  boost::system::error_code error;
+  m_socket->shutdown(protocol::socket::shutdown_both, error);
+  m_socket->close(error);
+  // after this, handlers will be called with an error code
+
+  // ensure that the Face object is alive at least until all pending
+  // handlers are dispatched
+  io.post(bind(&StreamFace<T>::keepFaceAliveUntilAllHandlersExecuted,
+               this, this->shared_from_this()));
+}
 
 } // namespace nfd