From 1b99ceae67794bc3767d4cc7ac70c23b4496f9ef Mon Sep 17 00:00:00 2001
From: Carsten Patzke <carsten.patzke@desy.de>
Date: Tue, 13 Mar 2018 16:39:19 +0100
Subject: [PATCH] Added receiver errors

---
 common/cpp/include/common/error.h      |  5 +--
 receiver/src/main.cpp                  | 10 ++++--
 receiver/src/network_producer_peer.cpp |  5 ++-
 receiver/src/receiver.cpp              | 30 ++++++----------
 receiver/src/receiver.h                | 49 +++++++++++++++++++++++---
 5 files changed, 69 insertions(+), 30 deletions(-)

diff --git a/common/cpp/include/common/error.h b/common/cpp/include/common/error.h
index 0db2fe455..3a0b1918c 100644
--- a/common/cpp/include/common/error.h
+++ b/common/cpp/include/common/error.h
@@ -13,6 +13,7 @@ enum class ErrorType {
     kHidraError,
     kHttpError,
     kIOError,
+    kReceiverError,
 
     kMemoryAllocationError,
     kEndOfFile
@@ -30,7 +31,7 @@ class ErrorInterface {
     virtual void Append(const std::string& value) noexcept = 0;
     virtual ErrorType GetErrorType() const noexcept = 0;
     virtual ~ErrorInterface() = default; // needed for unique_ptr to delete itself
-    /*TODO: Add these function, so it will be really easy and convenient to use the error class
+    /*TODO: Add these functions, so it will be really easy and convenient to use the error class
      * virtual inline bool operator == (const Error& rhs) const
      * virtual inline bool operator != (const Error& rhs) const
      * virtual inline bool operator == (const ErrorTemplateInterface& rhs) const
@@ -44,7 +45,7 @@ class ErrorTemplateInterface {
   public:
     virtual ErrorType GetErrorType() const noexcept = 0;
     virtual Error Generate() const noexcept = 0;
-    /*TODO: Add these function, so it will be really easy and convenient to use the error class
+    /*TODO: Add these functions, so it will be really easy and convenient to use the error class
      * virtual inline bool operator ErrorTemplateInterface() const
      */
 
diff --git a/receiver/src/main.cpp b/receiver/src/main.cpp
index c635f023d..871af6f08 100644
--- a/receiver/src/main.cpp
+++ b/receiver/src/main.cpp
@@ -6,11 +6,11 @@ int main (int argc, char* argv[]) {
 
     auto* receiver = new hidra2::Receiver();
 
-    hidra2::ReceiverError err;
+    hidra2::Error err;
 
     receiver->StartListener(address, &err);
-    if(err != hidra2::ReceiverError::kNoError) {
-        std::cerr << "Fail to start receiver" << std::endl;
+    if(err) {
+        std::cerr << "Fail to start receiver: " << err->Explain() << std::endl;
         return 1;
     }
     std::cout << "StartListener on " << address << std::endl;
@@ -20,6 +20,10 @@ int main (int argc, char* argv[]) {
 
     std::cout << "Stop listener..." << std::endl;
     receiver->StopListener(&err);//TODO might not work since Accept is a blocking call :/
+    if(err) {
+        std::cerr << "Fail to stop receiver: " << err->Explain() << std::endl;
+        return 1;
+    }
 
     return 0;
 }
diff --git a/receiver/src/network_producer_peer.cpp b/receiver/src/network_producer_peer.cpp
index c08f89549..080a07bce 100644
--- a/receiver/src/network_producer_peer.cpp
+++ b/receiver/src/network_producer_peer.cpp
@@ -51,6 +51,8 @@ void NetworkProducerPeer::internal_receiver_thread_() {
         }
 
         std::cout << "[" << GetConnectionId() << "] Got request: " << generic_request->op_code << std::endl;
+
+        //generic_response will be set here and the amount to send is returned
         size_t bytes_to_send = handle_generic_request_(generic_request.get(), generic_response.get());
 
         if(bytes_to_send == 0) {
@@ -92,7 +94,8 @@ size_t NetworkProducerPeer::handle_generic_request_(GenericNetworkRequest* reque
     Error io_err;
 
     static const size_t sizeof_generic_request = sizeof(GenericNetworkRequest);
-    //receive the rest of the message
+    //after receiving all GenericNetworkResponse fields from caller,
+    //we need now need to receive the rest of the request
     io->Receive(socket_fd_, (uint8_t*)request + sizeof_generic_request,
                 handler_information.request_size - sizeof_generic_request, &io_err);
 
diff --git a/receiver/src/receiver.cpp b/receiver/src/receiver.cpp
index a350bcf7c..e7be0646e 100644
--- a/receiver/src/receiver.cpp
+++ b/receiver/src/receiver.cpp
@@ -5,41 +5,33 @@
 
 const int hidra2::Receiver::kMaxUnacceptedConnectionsBacklog = 5;
 
-void hidra2::Receiver::StartListener(std::string listener_address, ReceiverError* err) {
-    *err = ReceiverError::kNoError;
+void hidra2::Receiver::StartListener(std::string listener_address, Error* err) {
+    *err = nullptr;
 
     if(listener_running_) {
-        *err = ReceiverError::kAlreadyListening;
+        *err = ReceiverErrorTemplates::kAlreadyListening.Generate();
         return;
     }
     listener_running_ = true;
 
-    Error io_error;
-
     FileDescriptor listener_fd = io->CreateSocket(AddressFamilies::INET, SocketTypes::STREAM, SocketProtocols::IP,
-                                                  &io_error);
-    if(io_error != nullptr) {
-        *err = ReceiverError::kFailToCreateSocket;
+                                                  err);
+    if(*err) {
         listener_running_ = false;
-        std::cerr << "Fail to create socket" << std::endl;
         return;
     }
 
-    io->InetBind(listener_fd, listener_address, &io_error);
-    if(io_error != nullptr) {
+    io->InetBind(listener_fd, listener_address, err);
+    if(*err) {
         io->CloseSocket(listener_fd, nullptr);
-        *err = ReceiverError::kFailToCreateSocket;
         listener_running_ = false;
-        std::cerr << "Fail to bind socket" << std::endl;
         return;
     }
 
-    io->Listen(listener_fd, kMaxUnacceptedConnectionsBacklog, &io_error);
-    if(io_error != nullptr) {
+    io->Listen(listener_fd, kMaxUnacceptedConnectionsBacklog, err);
+    if(*err) {
         io->CloseSocket(listener_fd, nullptr);
-        *err = ReceiverError::kFailToCreateSocket;
         listener_running_ = false;
-        std::cerr << "Fail to start listen" << std::endl;
         return;
     }
 
@@ -58,7 +50,7 @@ void hidra2::Receiver::AcceptThreadLogic() {
 
         Error io_error;
         auto client_info_tuple = io->InetAccept(listener_fd_, &io_error);
-        if(io_error != nullptr) {
+        if(io_error) {
             std::cerr << "An error occurred while accepting an incoming connection" << std::endl;
             return;
         }
@@ -68,7 +60,7 @@ void hidra2::Receiver::AcceptThreadLogic() {
     }
 }
 
-void hidra2::Receiver::StopListener(ReceiverError* err) {
+void hidra2::Receiver::StopListener(Error* err) {
     listener_running_ = false;
     io->CloseSocket(listener_fd_, nullptr);
     if(accept_thread_)
diff --git a/receiver/src/receiver.h b/receiver/src/receiver.h
index f968952cb..8fdf6be54 100644
--- a/receiver/src/receiver.h
+++ b/receiver/src/receiver.h
@@ -9,10 +9,49 @@
 
 namespace hidra2 {
 
-enum class ReceiverError {
-    kNoError,
+enum class ReceiverErrorType {
     kAlreadyListening,
-    kFailToCreateSocket,
+};
+
+class ReceiverError : public SimpleError {
+  private:
+    ReceiverErrorType receiver_error_type_;
+  public:
+    ReceiverError(const std::string& error, ReceiverErrorType receiver_error_type) : SimpleError(error,
+                ErrorType::kReceiverError) {
+        receiver_error_type_ = receiver_error_type;
+    }
+
+    ReceiverErrorType GetReceiverErrorType() const noexcept {
+        return receiver_error_type_;
+    }
+};
+
+class ReceiverErrorTemplate : public SimpleErrorTemplate {
+  protected:
+    ReceiverErrorType receiver_error_type_;
+  public:
+    ReceiverErrorTemplate(const std::string& error, ReceiverErrorType receiver_error_type) : SimpleErrorTemplate(error,
+                ErrorType::kIOError) {
+        receiver_error_type_ = receiver_error_type;
+    }
+
+    inline ReceiverErrorType GetReceiverErrorType() const noexcept {
+        return receiver_error_type_;
+    }
+
+    inline Error Generate() const noexcept override {
+        return Error(new ReceiverError(error_, receiver_error_type_));
+    }
+
+    inline bool operator == (const Error& rhs) const override {
+        return SimpleErrorTemplate::operator==(rhs)
+               && GetReceiverErrorType() == ((ReceiverError*)rhs.get())->GetReceiverErrorType();
+    }
+};
+
+namespace ReceiverErrorTemplates {
+auto const kAlreadyListening = ReceiverErrorTemplate{"Receiver is already listening", ReceiverErrorType::kAlreadyListening};
 };
 
 class Receiver : public HasIO {
@@ -34,8 +73,8 @@ class Receiver : public HasIO {
 
     Receiver() = default;
 
-    void StartListener(std::string listener_address, ReceiverError* err);
-    void StopListener(ReceiverError* err);
+    void StartListener(std::string listener_address, Error* err);
+    void StopListener(Error* err);
 };
 
 }
-- 
GitLab