From 9b6c992bb7b0a6ca7d00bb9196cc5e6e5cda69e5 Mon Sep 17 00:00:00 2001
From: Daniel M <daniel.q.mueller@stud.h-da.de>
Date: Tue, 11 May 2021 23:32:34 +0200
Subject: [PATCH] Add sendAll readAll functions

---
 inc/tcpstream.hpp | 32 ++++++++++++++++++++++++++++++++
 src/tcpstream.cpp | 43 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+)

diff --git a/inc/tcpstream.hpp b/inc/tcpstream.hpp
index d2b7408..05f69c5 100644
--- a/inc/tcpstream.hpp
+++ b/inc/tcpstream.hpp
@@ -106,6 +106,19 @@ public:
      */
     ssize_t send(const void *data, size_t len);
 
+    /**
+     * @brief Send exactly len bytes of data into the tcp connection.
+     * 
+     * If sending fails, an exception is thrown.
+     * 
+     * @param data Pointer to at least len bytes that will be sent over the 
+     * tcp connection.
+     * @param len The number of bytes that will be sent over the tcp connection.
+     *  
+     * @return The number of bytes that were actually sent over the connection.
+     */
+    void sendAll(const void *data, size_t len);
+
     /**
      * @brief Receive a maximum of len bytes of data from the tcp connection. It 
      * is possible that less than len bytes are received. This call will block 
@@ -123,6 +136,25 @@ public:
      */
     ssize_t read(void *data, size_t len);
 
+    /**
+     * @brief Read exactly len bytes from the tcp stream. If the connection is
+     * closed before len bytes are read, the number of bytes actually read is 
+     * returned. This will block until exactly len bytes are read or the 
+     * connection is closed.
+     * 
+     * If receiving failed or the connection is closed before at least one 
+     * byte was received, an exception is thrown.
+     * 
+     * @param data Pointer to at least len bytes where the data received over  
+     * the tcp connection will be stored.
+     * @param len The number of bytes that will be received over the tcp 
+     * connection.
+     *  
+     * @return The number of bytes that were actually received over the 
+     * connection. This can be less than len if the connection is closed.
+     */
+    ssize_t readAll(void *data, size_t len);
+
     /**
      * @brief Get the socket address of the connection target.
      * 
diff --git a/src/tcpstream.cpp b/src/tcpstream.cpp
index 09bd214..b470516 100644
--- a/src/tcpstream.cpp
+++ b/src/tcpstream.cpp
@@ -92,6 +92,27 @@ ssize_t TcpStream::send(const void *data, size_t len)
     return bytes_sent;
 }
 
+void TcpStream::sendAll(const void *data, size_t len)
+{
+    if (sockfd == 0)
+        throw std::runtime_error("Can't write to closed socket");
+    
+    size_t bytesSentTotal = 0;
+
+    while (bytesSentTotal < len)
+    {
+        ssize_t bytesSent = ::write(sockfd, (uint8_t*)data + bytesSentTotal, len-bytesSentTotal);
+
+        if (bytesSent < 0)
+        {
+            close();
+            throw std::runtime_error("Error while writing to socket");
+        }
+
+        bytesSentTotal += bytesSent;
+    }
+}
+
 ssize_t TcpStream::read(void *data, size_t len)
 {
     if (sockfd == 0)
@@ -106,6 +127,28 @@ ssize_t TcpStream::read(void *data, size_t len)
     return bytes_read;
 }
 
+ssize_t TcpStream::readAll(void *data, size_t len)
+{
+    if (sockfd == 0)
+        throw std::runtime_error("Can't read from closed socket");
+    
+    size_t bytesReadTotal = 0;
+    while (true)
+    {
+        ssize_t bytesRead = ::read(sockfd, (uint8_t*)data + bytesReadTotal, len-bytesReadTotal);
+
+        if (bytesRead == 0) break;
+        if (bytesRead < 0)
+        {
+            close();
+            throw std::runtime_error("Error while reading from socket");
+        }
+
+        bytesReadTotal += bytesRead;
+    }
+    return bytesReadTotal;
+}
+
 const SockAddr & TcpStream::getRemoteAddr() const
 {
     return remote;
-- 
GitLab