diff --git a/.gitignore b/.gitignore
index 8a3e47d4192b2b89bd8d537d36b37e4e61802b40..13bf1b11ad3dd89a04c62bc84790f85f08b1dc8e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,3 @@
-#Astyle
-.orig
-
-
 # Created by https://www.gitignore.io/api/c++,cmake,clion+all
 
 ### C++ ###
@@ -113,6 +109,9 @@ build
 
 # End of https://www.gitignore.io/api/c++,cmake,clion+all
 
+#Astyle
+*.orig
+
 ### Doxygen ###
 doxygen
 
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cb5aa714b0903e185dab371f7eacfff2c4450411..d4e6c35a31a5615fd037d2fa899c98fdbf564709 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,9 +8,20 @@ ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "GNU")
     set(CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS} -Wall")
 ENDIF(WIN32)
 
+#TODO: Better way then GLOBAL PROPERTY
+IF(WIN32)
+    find_package(Threads REQUIRED)
+    SET_PROPERTY(GLOBAL PROPERTY HIDRA2_COMMON_IO_LIBRARIES ${CMAKE_THREAD_LIBS_INIT} wsock32 ws2_32)
+ELSEIF(UNIX)
+    SET_PROPERTY(GLOBAL PROPERTY HIDRA2_COMMON_IO_LIBRARIES Threads::Threads)
+ENDIF(WIN32)
+
 option(BUILD_TESTS "Uses googletest to build tests" OFF)
 option(BUILD_INTEGRATION_TESTS "Include integration tests (CMAKE >3.7 is needed)" OFF)
 option(BUILD_DOCS "Uses doxygen to build the documentaion" OFF)
+option(BUILD_BROKER "Build broker" OFF)
+option(BUILD_WORKER_TOOLS "Build worker tools" OFF)
+option(BUILD_EXAMPLES "Build examples" OFF)
 
 set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMakeModules/)
 
@@ -30,7 +41,7 @@ endif()
 
 add_subdirectory(common/cpp)
 
-if (BUILD_BROKER)
+if (BUILD_BROKER)#TODO: Somehow make it clear that this is needed by examples/worker/getnext_broker
     add_subdirectory(broker)
 endif()
 
@@ -38,10 +49,7 @@ add_subdirectory(producer/api)
 
 add_subdirectory(worker)
 
-
-IF(UNIX)
-    add_subdirectory(receiver)
-ENDIF(UNIX)
+add_subdirectory(receiver)
 
 if(BUILD_INTEGRATION_TESTS)
     add_subdirectory(tests)
diff --git a/CMakeModules/testing_cpp.cmake b/CMakeModules/testing_cpp.cmake
index 5efbb83b05f1afd6480039b1d68d65fe60f6a383..1eb817ad1a5acee7ae379f6c1dbb558364dad235 100644
--- a/CMakeModules/testing_cpp.cmake
+++ b/CMakeModules/testing_cpp.cmake
@@ -18,6 +18,39 @@ if (BUILD_TESTS)
     endif ()
 endif ()
 
+#TODO: Call add_plain_unit_test in gtest
+function(add_plain_unit_test target test_source_files linktarget)
+    if (BUILD_TESTS)
+        include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
+        link_directories(${gtest_SOURCE_DIR}/lib)
+
+        add_executable(test-${target} ${test_source_files})
+
+        if (NOT ${libs} STREQUAL "")
+            target_link_libraries(test-${target} ${libs})
+        endif ()
+
+        IF (WIN32 AND ${CMAKE_BUILD_TYPE} STREQUAL "Debug")
+            set(GTEST_LIBS gtestd gtest_maind gmockd)
+        ELSE ()
+            set(GTEST_LIBS gtest gmock gtest_main)
+        ENDIF (WIN32 AND ${CMAKE_BUILD_TYPE} STREQUAL "Debug")
+        target_link_libraries(test-${target} ${GTEST_LIBS} ${CMAKE_THREAD_LIBS_INIT})
+
+        GET_PROPERTY(HIDRA2_COMMON_IO_LIBRARIES GLOBAL PROPERTY HIDRA2_COMMON_IO_LIBRARIES)
+        message(STATUS "HIDRA2_COMMON_IO_LIBRARIES: '${HIDRA2_COMMON_IO_LIBRARIES}'")
+        target_link_libraries(test-${target} ${HIDRA2_COMMON_IO_LIBRARIES})
+
+        if (NOT ${test_libraries} STREQUAL "")
+            target_link_libraries(test-${target} ${test_libraries})
+        endif ()
+        add_test(NAME test-${target} COMMAND test-${target})
+        set_tests_properties(test-${target} PROPERTIES LABELS "unit;all")
+
+        message(STATUS "Added test 'test-${target}'")
+    endif()
+endfunction()
+
 function(gtest target test_source_files linktarget)
     if (BUILD_TESTS)
         include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
@@ -48,6 +81,13 @@ function(gtest target test_source_files linktarget)
         ENDIF (WIN32 AND ${CMAKE_BUILD_TYPE} STREQUAL "Debug")
         target_link_libraries(test-${target} ${GTEST_LIBS} ${CMAKE_THREAD_LIBS_INIT})
 
+        GET_PROPERTY(HIDRA2_COMMON_IO_LIBRARIES GLOBAL PROPERTY HIDRA2_COMMON_IO_LIBRARIES)
+        message(STATUS "HIDRA2_COMMON_IO_LIBRARIES: '${HIDRA2_COMMON_IO_LIBRARIES}'")
+        target_link_libraries(test-${target} ${HIDRA2_COMMON_IO_LIBRARIES})
+
+        if (NOT ${test_libraries} STREQUAL "")
+            target_link_libraries(test-${target} ${test_libraries})
+        endif ()
         add_test(NAME test-${target} COMMAND test-${target})
         set_tests_properties(test-${target} PROPERTIES LABELS "unit;all")
 
@@ -163,6 +203,11 @@ function(add_script_test testname arguments)
                     separate_arguments(memargs)
                     add_test(NAME memtest-${testname} COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/check_linux.sh
                             ${memargs})
+                    set_tests_properties(memtest-${testname} PROPERTIES
+                            LABELS "memcheck_${label};all"
+                            DEPENDS test-${testname}
+                            )
+
                 endif ()
             endif ()
         ENDIF ()
diff --git a/CMakeModules/testing_go.cmake b/CMakeModules/testing_go.cmake
index 3fcdb6e501075a3e234e2c95dab63b52be6fcd8a..56d7c168803185e6fd58055ddb028a264ab4d7cd 100644
--- a/CMakeModules/testing_go.cmake
+++ b/CMakeModules/testing_go.cmake
@@ -24,6 +24,7 @@ function(gotest target test_source_files)
                         COMMAND ${CMAKE_MODULE_PATH}/coverage_go.sh
                         ${CMAKE_CURRENT_BINARY_DIR} ${HIDRA2_MINIMUM_COVERAGE} ${gopath}
                         WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
+        set_tests_properties(coveragetest-${target} PROPERTIES LABELS "coverage;all")
         endif()
     endif ()
 endfunction()
diff --git a/README.md b/README.md
index f527b949f40368117555570d4b81c18f31c01266..680a681206b2457a68668700aff3b29dae75f735 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# HIDRA2
+# hidra2
 
 # C++ Projects
  
@@ -8,7 +8,7 @@
  
  - /producer/producer-api
  
- **Library:** Producer library which can send data to the receiver
+ **Library:** ProducerImpl library which can send data to the receiver
  
  - /receiver
  
diff --git a/common/cpp/CMakeLists.txt b/common/cpp/CMakeLists.txt
index 0b489c5d47d4bc9e0ef3ff57d59b27f003dc972e..2e79b345e35a1a91c74e90320c463f8f66b3800d 100644
--- a/common/cpp/CMakeLists.txt
+++ b/common/cpp/CMakeLists.txt
@@ -1,5 +1,6 @@
 add_subdirectory(src/system_io)
 
+add_subdirectory(src/common)
 
 add_subdirectory(src/json_parser)
 
@@ -11,3 +12,4 @@ endif()
 
 install(DIRECTORY ${HIDRA2_CXX_COMMON_INCLUDE_DIR}/common
         DESTINATION ${CMAKE_INSTALL_PREFIX}/include )
+
diff --git a/common/cpp/include/common/error.h b/common/cpp/include/common/error.h
index 8ef74d4f5963df36225a46efa25515cdf870129f..e4602afd5a948194d8d7eb2214a6c40d69945c15 100644
--- a/common/cpp/include/common/error.h
+++ b/common/cpp/include/common/error.h
@@ -3,35 +3,87 @@
 
 #include <string>
 #include <memory>
+#include <utility>
 
 namespace hidra2 {
 
 enum class ErrorType {
+    kUnknownError,
+
     kHidraError,
-    kEOF,
-    kHttpError
+    kHttpError,
+    kIOError,
+    kReceiverError,
+    kProducerError,
+
+    kMemoryAllocationError,
+    kEndOfFile
 };
 
+class ErrorInterface;
+class ErrorTemplateInterface;
+
+// nullptr == noError
+// Example check:
+//  void TestError(Error* err) {
+//      if(*err) {
+//          [...] //An error occurred
+//      }
+//  }
+using Error = std::unique_ptr<ErrorInterface>;
+
 class ErrorInterface {
   public:
     virtual std::string Explain() const noexcept = 0;
     virtual void Append(const std::string& value) noexcept = 0;
-    virtual ErrorType GetErrorType() noexcept = 0;
+    virtual ErrorType GetErrorType() const noexcept = 0;
     virtual ~ErrorInterface() = default; // needed for unique_ptr to delete itself
+};
 
+
+class ErrorTemplateInterface {
+  public:
+    virtual ErrorType GetErrorType() const noexcept = 0;
+    virtual Error Generate() const noexcept = 0;
+    virtual std::string Text() const noexcept = 0;
+
+    virtual inline bool operator == (const Error& rhs) const {
+        return rhs != nullptr &&
+               GetErrorType() == rhs->GetErrorType();
+    }
+
+    virtual inline bool operator != (const Error& rhs) const {
+        return !(operator==(rhs));
+    }
 };
 
-using Error = std::unique_ptr<ErrorInterface>;
+static inline bool operator == (const Error& lhs, const ErrorTemplateInterface& rhs) {
+    return rhs.operator == (lhs);
+}
+
+static inline bool operator != (const Error& lhs, const ErrorTemplateInterface& rhs) {
+    return rhs.operator != (lhs);
+}
+
+static inline std::ostream& operator<<(std::ostream& os, const Error& err) {
+    if(err) {
+        os << err->Explain();
+    } else {
+        static std::string no_error = "No error";
+        os << no_error;
+    }
+    return os;
+}
 
 class SimpleError: public ErrorInterface {
   private:
     std::string error_;
     ErrorType error_type_ = ErrorType::kHidraError;
   public:
-    explicit SimpleError(const std::string& error): error_{error} {
+    explicit SimpleError(std::string error): error_{std::move(error)} {
 
     }
-    SimpleError(const std::string& error, ErrorType error_type ): error_{error}, error_type_{error_type} {
+    SimpleError(std::string error, ErrorType error_type ): error_{std::move(error)}, error_type_{error_type} {
     }
 
     void Append(const std::string& value) noexcept override {
@@ -41,12 +93,49 @@ class SimpleError: public ErrorInterface {
     std::string Explain() const noexcept override  {
         return error_;
     }
-    ErrorType GetErrorType()noexcept override  {
+
+    ErrorType GetErrorType() const noexcept override  {
         return error_type_;
     }
+};
 
+
+/*
+ * IMPORTANT:
+ * Never use the same ErrorType for two different errors,
+ * otherwise the == operator might not work as expected!
+ */
+class SimpleErrorTemplate : public ErrorTemplateInterface {
+  protected:
+    std::string error_;
+    ErrorType error_type_ = ErrorType::kHidraError;
+  public:
+    explicit SimpleErrorTemplate(std::string error): error_{std::move(error)} {
+
+    }
+
+    virtual std::string Text() const noexcept override {
+        return error_;
+    }
+
+
+    SimpleErrorTemplate(std::string error, ErrorType error_type ): error_{std::move(error)}, error_type_{error_type} {
+    }
+
+    inline ErrorType GetErrorType() const noexcept override {
+        return error_type_;
+    }
+
+    inline Error Generate() const noexcept override {
+        return Error(new SimpleError{error_, error_type_});
+    }
 };
 
+static inline std::ostream& operator<<(std::ostream& os, const SimpleErrorTemplate& err) {
+    return os << err.Text();
+}
+
+
 inline Error TextError(const std::string& error) {
     return Error{new SimpleError{error}};
 }
@@ -55,6 +144,15 @@ inline Error TextErrorWithType(const std::string& error, ErrorType error_type) {
     return Error{new SimpleError{error, error_type}};
 }
 
+namespace ErrorTemplates {
+auto const kMemoryAllocationError = SimpleErrorTemplate {
+    "kMemoryAllocationError", ErrorType::kMemoryAllocationError
+};
+auto const kEndOfFile = SimpleErrorTemplate {
+    "End of file", ErrorType::kEndOfFile
+};
+
+}
 
 }
 #endif //HIDRA2_ERROR_H
diff --git a/common/cpp/include/common/io_error.h b/common/cpp/include/common/io_error.h
new file mode 100644
index 0000000000000000000000000000000000000000..40c9d4dd7e2c62ad73531d0a4aa18ebbbdeff2d0
--- /dev/null
+++ b/common/cpp/include/common/io_error.h
@@ -0,0 +1,142 @@
+#ifndef HIDRA2_SYSTEM__IO_ERROR_H
+#define HIDRA2_SYSTEM__IO_ERROR_H
+
+#include "common/error.h"
+
+namespace hidra2 {
+
+
+enum class IOErrorType {
+    kUnknownIOError,
+    kBadFileNumber,
+    kResourceTemporarilyUnavailable,
+    kFileNotFound,
+    kReadError,
+    kPermissionDenied,
+    kUnsupportedAddressFamily,
+    kInvalidAddressFormat,
+    kAddressAlreadyInUse,
+    kConnectionRefused,
+    kConnectionResetByPeer,
+    kTimeout,
+    kFileAlreadyExists,
+    kNoSpaceLeft,
+    kSocketOperationOnNonSocket,
+    kInvalidMemoryAddress,
+    kUnableToResolveHostname,
+    kSocketOperationUnknownAtLevel,
+    kSocketOperationValueOutOfBound,
+    kAddressNotValid
+
+};
+
+class IOError : public SimpleError {
+  private:
+    IOErrorType io_error_type_;
+  public:
+    IOError(const std::string& error, IOErrorType io_error_type) : SimpleError(error, ErrorType::kIOError) {
+        io_error_type_ = io_error_type;
+    }
+
+    IOErrorType GetIOErrorType() const noexcept {
+        return io_error_type_;
+    }
+};
+
+class IOErrorTemplate : public SimpleErrorTemplate {
+  protected:
+    IOErrorType io_error_type_;
+  public:
+    IOErrorTemplate(const std::string& error, IOErrorType io_error_type) : SimpleErrorTemplate(error, ErrorType::kIOError) {
+        io_error_type_ = io_error_type;
+    }
+
+    inline IOErrorType GetIOErrorType() const noexcept {
+        return io_error_type_;
+    }
+
+    inline Error Generate() const noexcept override {
+        return Error(new IOError(error_, io_error_type_));
+    }
+
+    inline bool operator == (const Error& rhs) const override {
+        return SimpleErrorTemplate::operator==(rhs)
+               && GetIOErrorType() == ((IOError*)rhs.get())->GetIOErrorType();
+    }
+};
+
+static inline std::ostream& operator<<(std::ostream& os, const IOErrorTemplate& err) {
+    return os << err.Text();
+}
+
+
+namespace IOErrorTemplates {
+auto const kUnknownIOError = IOErrorTemplate {
+    "Unknown Error", IOErrorType::kUnknownIOError
+};
+
+auto const kFileNotFound = IOErrorTemplate {
+    "No such file or directory", IOErrorType::kFileNotFound
+};
+auto const kReadError = IOErrorTemplate {
+    "Read error", IOErrorType::kReadError
+};
+auto const kBadFileNumber = IOErrorTemplate {
+    "Bad file number", IOErrorType::kBadFileNumber
+};
+auto const kResourceTemporarilyUnavailable = IOErrorTemplate {
+    "Resource temporarily unavailable", IOErrorType::kResourceTemporarilyUnavailable
+};
+auto const kPermissionDenied = IOErrorTemplate {
+    "Permission denied", IOErrorType::kPermissionDenied
+};
+auto const kUnsupportedAddressFamily = IOErrorTemplate {
+    "Unsupported address family", IOErrorType::kUnsupportedAddressFamily
+};
+auto const kInvalidAddressFormat = IOErrorTemplate {
+    "Invalid address format", IOErrorType::kInvalidAddressFormat
+};
+auto const kAddressAlreadyInUse = IOErrorTemplate {
+    "Address already in use", IOErrorType::kAddressAlreadyInUse
+};
+auto const kConnectionRefused = IOErrorTemplate {
+    "Connection refused", IOErrorType::kConnectionRefused
+};
+auto const kConnectionResetByPeer = IOErrorTemplate {
+    "kConnectionResetByPeer", IOErrorType::kConnectionResetByPeer
+};
+auto const kTimeout = IOErrorTemplate {
+    "kTimeout", IOErrorType::kTimeout
+};
+auto const kFileAlreadyExists = IOErrorTemplate {
+    "kFileAlreadyExists", IOErrorType::kFileAlreadyExists
+};
+auto const kNoSpaceLeft = IOErrorTemplate {
+    "kNoSpaceLeft", IOErrorType::kNoSpaceLeft
+};
+auto const kSocketOperationOnNonSocket = IOErrorTemplate {
+    "kSocketOperationOnNonSocket", IOErrorType::kSocketOperationOnNonSocket
+};
+auto const kInvalidMemoryAddress = IOErrorTemplate {
+    "kInvalidMemoryAddress", IOErrorType::kInvalidMemoryAddress
+};
+auto const kUnableToResolveHostname = IOErrorTemplate {
+    "kUnableToResolveHostname", IOErrorType::kUnableToResolveHostname
+};
+auto const kSocketOperationUnknownAtLevel =  IOErrorTemplate {
+    "kSocketOperationUnknownAtLevel", IOErrorType::kSocketOperationUnknownAtLevel
+};
+
+auto const kSocketOperationValueOutOfBound =  IOErrorTemplate {
+    "kSocketOperationValueOutOfBound", IOErrorType::kSocketOperationValueOutOfBound
+};
+
+auto const kAddressNotValid =  IOErrorTemplate {
+    "Address not valid", IOErrorType::kAddressNotValid
+};
+
+}
+
+}
+
+#endif //HIDRA2_SYSTEM__IO_ERROR_H
diff --git a/common/cpp/include/common/networking.h b/common/cpp/include/common/networking.h
index b3cd443c0335c619403043e60610ab4a7734d404..1e2c806e4072449e4c3a42503ad6cf4824077cc8 100644
--- a/common/cpp/include/common/networking.h
+++ b/common/cpp/include/common/networking.h
@@ -1,43 +1,54 @@
-#ifndef HIDRA2__COMMON_NETWORKING_H
-#define HIDRA2__COMMON_NETWORKING_H
+#ifndef HIDRA2_COMMON__NETWORKING_H
+#define HIDRA2_COMMON__NETWORKING_H
 
 #include <cstdint>
-#include "os.h"
 
 namespace hidra2 {
-enum OP_CODE : uint8_t {
-    OP_CODE__HELLO,
-};
 
-enum ERROR_CODE : uint16_t {
-    ERR__NO_ERROR,
-    ERR__UNSUPPORTED_VERSION,
-    ERR__INTERNAL_SERVER_ERROR = 65535,
-};
+typedef uint64_t NetworkRequestId;
 
-struct NetworkRequest {
-    OP_CODE     op_code;
-    uint64_t    request_id;
-    char        data[];
+enum Opcode : uint8_t {
+    kNetOpcodeUnknownOp,
+    kNetOpcodeSendData,
+    kNetOpcodeCount,
 };
 
-struct NetworkResponse {
-    OP_CODE     op_code;
-    uint64_t    request_id;
-    ERROR_CODE  error_code;
-    char        data[];
+enum NetworkErrorCode : uint16_t {
+    kNetErrorNoError,
+    kNetErrorFileIdAlreadyInUse,
+    kNetErrorAllocateStorageFailed,
+    kNetErrorInternalServerError = 65535,
 };
 
-struct OP_HelloRequest {
-    uint32_t client_version;
+//TODO need to use an serialization framework to ensure struct consistency on different computers
+
+/**
+ * @defgroup RPC
+ * RPC always return a response to a corresponding request
+ * @{
+ */
+struct GenericNetworkRequestHeader {
+    Opcode              op_code;
+    NetworkRequestId    request_id;
+    uint64_t    data_id;
+    uint64_t    data_size;
+};
 
-    OS_TYPE os : 4;
-    bool is_x64 : 1;
+struct GenericNetworkResponse {
+    Opcode              op_code;
+    NetworkRequestId    request_id;
+    NetworkErrorCode    error_code;
 };
 
-struct OP_HelloResponse {
-    uint32_t server_version;
+/**
+ * Possible error codes:
+ * - ::NET_ERR__FILENAME_ALREADY_IN_USE
+ * - ::NET_ERR__ALLOCATE_STORAGE_FAILED
+ */
+struct SendDataResponse :  GenericNetworkResponse {
 };
+/** @} */
+
 }
 
-#endif //HIDRA2__COMMON_NETWORKING_H
+#endif //HIDRA2_COMMON__NETWORKING_H
diff --git a/common/cpp/include/common/os.h b/common/cpp/include/common/os.h
deleted file mode 100644
index ddd8c2a3e814b87031b4b48cefbf8f2e2b64de96..0000000000000000000000000000000000000000
--- a/common/cpp/include/common/os.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef HIDRA2__COMMON_OS_H
-#define HIDRA2__COMMON_OS_H
-
-#include <cstdint>
-
-namespace hidra2 {
-enum OS_TYPE : uint8_t {
-    OS_UNKOWN,
-    OS_LINUX,
-    OS_WINDOWS,
-
-    OS_INVALID = 16, /* Never use more then 4 bit */
-};
-}
-
-#endif //HIDRA2__COMMON_OS_H
diff --git a/common/cpp/include/io/io.h b/common/cpp/include/io/io.h
new file mode 100644
index 0000000000000000000000000000000000000000..61e03685cff91788b68b8225e2e7ff7ab33a6004
--- /dev/null
+++ b/common/cpp/include/io/io.h
@@ -0,0 +1,106 @@
+#ifndef HIDRA2_SYSTEM__IO_H
+#define HIDRA2_SYSTEM__IO_H
+
+#include <cinttypes>
+
+#include <string>
+#include <vector>
+#include <chrono>
+#include <thread>
+
+#include "common/data_structs.h"
+#include "common/io_error.h"
+
+namespace hidra2 {
+
+//Need to be "enum" since multiple flags are allowed
+enum FileOpenMode {
+    IO_OPEN_MODE_READ = 1 << 0,
+    IO_OPEN_MODE_WRITE = 1 << 1,
+    IO_OPEN_MODE_RW = IO_OPEN_MODE_READ | IO_OPEN_MODE_WRITE,
+    IO_OPEN_MODE_CREATE = 1 << 2,
+    IO_OPEN_MODE_CREATE_AND_FAIL_IF_EXISTS = 1 << 3,
+    /**
+     * Will set the length of a file to 0
+     * Only works if file is open with READ and WRITE mode
+     */
+    IO_OPEN_MODE_SET_LENGTH_0 = 1 << 4,
+};
+
+enum class AddressFamilies {
+    INET,
+};
+
+enum class SocketTypes {
+    STREAM,
+};
+
+enum class SocketProtocols {
+    IP,
+};
+
+using FileDescriptor = int;
+using SocketDescriptor = int;
+
+class IO {
+  public:
+
+    /*
+     * Special
+     */
+    virtual std::unique_ptr<std::thread> NewThread       (std::function<void()> function) const = 0;
+
+    /*
+     * Network
+     */
+    virtual SocketDescriptor  CreateSocket(AddressFamilies address_family, SocketTypes socket_type,
+                                           SocketProtocols socket_protocol, Error* err) const = 0;
+    virtual void            Listen(SocketDescriptor socket_fd, int backlog, Error* err) const = 0;
+    virtual void            InetBind(SocketDescriptor socket_fd, const std::string& address, Error* err) const = 0;
+    virtual SocketDescriptor  CreateAndBindIPTCPSocketListener(const std::string& address, int backlog,
+            Error* err) const = 0;
+    virtual std::unique_ptr<std::tuple<std::string, SocketDescriptor>> InetAcceptConnection(SocketDescriptor socket_fd,
+            Error* err) const = 0;
+    virtual std::string     ResolveHostnameToIp(const std::string& hostname, Error* err) const = 0;
+    virtual void            InetConnect(SocketDescriptor socket_fd, const std::string& address, Error* err) const = 0;
+    virtual SocketDescriptor  CreateAndConnectIPTCPSocket(const std::string& address, Error* err) const = 0;
+    virtual size_t          Receive(SocketDescriptor socket_fd, void* buf, size_t length, Error* err) const = 0;
+    virtual size_t          ReceiveWithTimeout(SocketDescriptor socket_fd,
+                                               void* buf,
+                                               size_t length,
+                                               long timeout_in_usec,
+                                               Error* err) const = 0;
+    virtual size_t          Send(SocketDescriptor socket_fd, const void* buf, size_t length, Error* err) const = 0;
+
+    virtual void            Skip(SocketDescriptor socket_fd, size_t length, Error* err) const = 0;
+    /**
+     * @param err Since CloseSocket if often used in an error case, it's able to accept err as nullptr.
+     */
+    virtual void            CloseSocket(SocketDescriptor socket_fd, Error* err) const = 0;
+
+    /*
+     * Filesystem
+     */
+    virtual FileDescriptor  Open            (const std::string& filename, int open_flags, Error* err) const = 0;
+    /**
+     * @param err Since Close if often used in an error case, it's able to accept err as nullptr.
+     */
+    virtual void            Close           (FileDescriptor fd, Error* err) const = 0;
+
+    virtual size_t          Read            (FileDescriptor fd, void* buf, size_t length, Error* err) const = 0;
+    virtual size_t          Write           (FileDescriptor fd, const void* buf, size_t length, Error* err) const = 0;
+
+    virtual Error          WriteDataToFile  (const std::string& fname, const FileData& data, size_t length) const = 0;
+
+    virtual void            CreateNewDirectory      (const std::string& directory_name, Error* err) const = 0;
+    virtual FileData        GetDataFromFile         (const std::string& fname, uint64_t fsize, Error* err) const = 0;
+    virtual void CollectFileInformationRecursively(const std::string& path, std::vector<FileInfo>* files,
+                                                   Error* err) const = 0;
+    virtual std::vector<FileInfo>   FilesInFolder   (const std::string& folder, Error* err) const = 0;
+    virtual std::string     ReadFileToString        (const std::string& fname, Error* err) const = 0;
+
+};
+
+}
+
+#endif //HIDRA2_SYSTEM__IO_H
diff --git a/common/cpp/include/io/io_factory.h b/common/cpp/include/io/io_factory.h
new file mode 100644
index 0000000000000000000000000000000000000000..4dd614beecaa05e1fcbf51cfbdbabfb6f881e495
--- /dev/null
+++ b/common/cpp/include/io/io_factory.h
@@ -0,0 +1,12 @@
+#ifndef HIDRA2_IO_FACTORY_H
+#define HIDRA2_IO_FACTORY_H
+
+#include "io.h"
+
+namespace hidra2 {
+
+IO* GenerateDefaultIO();
+
+}
+
+#endif //HIDRA2_IO_FACTORY_H
\ No newline at end of file
diff --git a/common/cpp/include/system_wrappers/io.h b/common/cpp/include/system_wrappers/io.h
deleted file mode 100644
index 5b0f4739903dbb21d0bf86d9d4f6ef6d59b5427e..0000000000000000000000000000000000000000
--- a/common/cpp/include/system_wrappers/io.h
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef HIDRA2_SYSTEM_WRAPPERS__IO_H
-#define HIDRA2_SYSTEM_WRAPPERS__IO_H
-
-#include <cinttypes>
-
-#include <string>
-#include <vector>
-#include <chrono>
-
-#include "common/data_structs.h"
-#include "common/error.h"
-
-namespace hidra2 {
-
-namespace IOErrors {
-auto const kFileNotFound = "No such file or directory";
-auto const kReadError = "Read error";
-auto const kPermissionDenied = "Permission denied";
-auto const kUnknownError = "Unknown error";
-auto const kMemoryAllocationError = "Memory Allocation Error";
-}
-
-Error IOErrorFromErrno();
-
-
-class IO {
-  public:
-
-    virtual FileData GetDataFromFile(const std::string& fname, uint64_t fsize, Error* err) const noexcept = 0;
-    virtual uint64_t Read(int fd, uint8_t* array, uint64_t fsize, Error* err) const noexcept = 0;
-    virtual std::string ReadFileToString(const std::string& fname, Error* err)const noexcept = 0;
-    virtual int open(const char* __file, int __oflag) const noexcept = 0;
-    virtual int close(int __fd) const noexcept = 0;
-
-// this is not standard function - to be implemented differently in windows and linux
-    virtual FileInfos FilesInFolder(const std::string& folder, Error* err) const = 0;
-};
-
-}
-
-#endif //HIDRA2_SYSTEM_WRAPPERS__IO_H
diff --git a/common/cpp/include/system_wrappers/system_io.h b/common/cpp/include/system_wrappers/system_io.h
deleted file mode 100644
index baf715b12b7650ccf7915ec2e0fe21c76d6c43d9..0000000000000000000000000000000000000000
--- a/common/cpp/include/system_wrappers/system_io.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef HIDRA2_SYSTEM_WRAPPERS__SYSTEM_IO_H
-#define HIDRA2_SYSTEM_WRAPPERS__SYSTEM_IO_H
-
-#include "io.h"
-
-namespace hidra2 {
-
-class SystemIO final : public IO {
-  public:
-    FileData GetDataFromFile(const std::string& fname, uint64_t fsize, Error* err) const noexcept override;
-    std::string ReadFileToString(const std::string& fname, Error* err) const noexcept override;
-    int open(const char* __file, int __oflag) const noexcept override;
-    int close(int __fd) const noexcept override;
-    uint64_t Read(int fd, uint8_t* array, uint64_t fsize, Error* err) const noexcept override;
-    std::vector<FileInfo> FilesInFolder(const std::string& folder, Error* err) const override;
-  private:
-    void CollectFileInformationRecursivly(const std::string& path,
-                                          std::vector<FileInfo>* files, Error* err) const;
-    int64_t read(int __fd, void* buf, size_t count) const noexcept;
-    int64_t write(int __fd, const void* __buf, size_t __n) const noexcept;
-    int OpenFile(const std::string& fname, Error* err) const noexcept;
-
-};
-
-FileInfo GetFileInfo(const std::string& name, Error* err);
-
-}
-
-#endif //HIDRA2_SYSTEM_WRAPPERS__SYSTEM_IO_H
diff --git a/common/cpp/include/unittests/MockIO.h b/common/cpp/include/unittests/MockIO.h
index 5a9ca436b1279a58da045ccecf7416f282708bbd..5da606c100fc57e9bc9c23ff310b09f52d71ef90 100644
--- a/common/cpp/include/unittests/MockIO.h
+++ b/common/cpp/include/unittests/MockIO.h
@@ -4,69 +4,208 @@
 #include <gtest/gtest.h>
 #include <gmock/gmock.h>
 
-#include "system_wrappers/io.h"
-
+#include "io/io.h"
 namespace hidra2 {
-
 class MockIO : public IO {
   public:
-    std::string ReadFileToString(const std::string& fname, Error* err)const noexcept  override {
-        SimpleError* error;
-        auto data = ReadFileToString_t(fname,  &error);
+    std::unique_ptr<std::thread> NewThread(std::function<void()> function) const override {
+        return std::unique_ptr<std::thread>(NewThread_t(function));
+    }
+    MOCK_CONST_METHOD1(NewThread_t, std::thread * (std::function<void()> function));
+
+    SocketDescriptor CreateSocket(AddressFamilies address_family, SocketTypes socket_type, SocketProtocols socket_protocol,
+                                  Error* err) const override {
+        ErrorInterface* error = nullptr;
+        auto data = CreateSocket_t(address_family, socket_type, socket_protocol, &error);
         err->reset(error);
         return data;
     }
+    MOCK_CONST_METHOD4(CreateSocket_t, SocketDescriptor(AddressFamilies address_family, SocketTypes socket_type,
+                       SocketProtocols socket_protocol, ErrorInterface** err));
 
-    FileData GetDataFromFile(const std::string& fname, uint64_t fsize, Error* err) const noexcept override {
-        SimpleError* error;
-        auto data = GetDataFromFile_t(fname, fsize, &error);
+    void Listen(SocketDescriptor socket_fd, int backlog, Error* err) const override {
+        ErrorInterface* error = nullptr;
+        Listen_t(socket_fd, backlog, &error);
         err->reset(error);
-        return FileData(data);
     }
-    int open(const char* __file, int __oflag) const noexcept override {
-        return 0;
+    MOCK_CONST_METHOD3(Listen_t, void(SocketDescriptor socket_fd, int backlog, ErrorInterface** err));
+
+
+    void InetBind(SocketDescriptor socket_fd, const std::string& address, Error* err) const override {
+        ErrorInterface* error = nullptr;
+        InetBind_t(socket_fd, address, &error);
+        err->reset(error);
     }
-    int close(int __fd) const noexcept override {
-        return 0;
+    MOCK_CONST_METHOD3(InetBind_t, void(SocketDescriptor socket_fd, const std::string& address, ErrorInterface** err));
+
+    SocketDescriptor CreateAndBindIPTCPSocketListener(const std::string& address, int backlog, Error* err) const override {
+        ErrorInterface* error = nullptr;
+        auto data = CreateAndBindIPTCPSocketListener_t(address, backlog, &error);
+        err->reset(error);
+        return data;
     }
-    uint64_t Read(int fd, uint8_t* array, uint64_t fsize, Error* err) const noexcept override {
-        return 0;
+    MOCK_CONST_METHOD3(CreateAndBindIPTCPSocketListener_t, SocketDescriptor(const std::string& address, int backlog,
+                       ErrorInterface** err));
+
+
+    std::unique_ptr<std::tuple<std::string, SocketDescriptor>> InetAcceptConnection(SocketDescriptor socket_fd,
+    Error* err) const override {
+        ErrorInterface* error = nullptr;
+        auto data = InetAcceptConnection_t(socket_fd, &error);
+        err->reset(error);
+        return std::unique_ptr<std::tuple<std::string, SocketDescriptor>>(data);
     }
+    MOCK_CONST_METHOD2(InetAcceptConnection_t, std::tuple<std::string, SocketDescriptor>* (SocketDescriptor socket_fd,
+                       ErrorInterface** err));
 
-    FileInfos FilesInFolder(const std::string& folder, Error* err) const override {
-        SimpleError* error;
-        auto data = FilesInFolder_t(folder, &error);
+    std::string ResolveHostnameToIp(const std::string& hostname, Error* err) const override {
+        ErrorInterface* error = nullptr;
+        auto data = ResolveHostnameToIp_t(hostname, &error);
+        err->reset(error);
+        return data;
+    }
+    MOCK_CONST_METHOD2(ResolveHostnameToIp_t, std::string(const std::string& hostname, ErrorInterface** err));
+
+    void InetConnect(SocketDescriptor socket_fd, const std::string& address, Error* err) const override {
+        ErrorInterface* error = nullptr;
+        InetConnect_t(socket_fd, address, &error);
+        err->reset(error);
+    }
+    MOCK_CONST_METHOD3(InetConnect_t, void(SocketDescriptor socket_fd, const std::string& address, ErrorInterface** err));
+
+    SocketDescriptor CreateAndConnectIPTCPSocket(const std::string& address, Error* err) const override {
+        ErrorInterface* error = nullptr;
+        auto data = CreateAndConnectIPTCPSocket_t(address, &error);
+        err->reset(error);
+        return data;
+    }
+    MOCK_CONST_METHOD2(CreateAndConnectIPTCPSocket_t, SocketDescriptor(const std::string& address, ErrorInterface** err));
+
+    size_t Receive(SocketDescriptor socket_fd, void* buf, size_t length, Error* err) const override {
+        ErrorInterface* error = nullptr;
+        auto data = Receive_t(socket_fd, buf, length, &error);
+        err->reset(error);
+        return data;
+    }
+    MOCK_CONST_METHOD4(Receive_t, size_t(SocketDescriptor socket_fd, void* buf, size_t length, ErrorInterface** err));
+
+    size_t ReceiveWithTimeout(SocketDescriptor socket_fd, void* buf, size_t length, long timeout_in_usec,
+                              Error* err) const override {
+        ErrorInterface* error = nullptr;
+        auto data = ReceiveWithTimeout_t(socket_fd, buf, length, timeout_in_usec, &error);
+        err->reset(error);
+        return data;
+    }
+    MOCK_CONST_METHOD5(ReceiveWithTimeout_t, size_t(SocketDescriptor socket_fd, void* buf, size_t length,
+                                                    long timeout_in_usec,
+                                                    ErrorInterface** err));
+
+    size_t Send(SocketDescriptor socket_fd, const void* buf, size_t length, Error* err) const override {
+        ErrorInterface* error = nullptr;
+        auto data = Send_t(socket_fd, buf, length, &error);
+        err->reset(error);
+        return data;
+    }
+    MOCK_CONST_METHOD4(Send_t, size_t(SocketDescriptor socket_fd, const void* buf, size_t length, ErrorInterface** err));
+
+    void Skip(SocketDescriptor socket_fd, size_t length, Error* err) const override {
+        ErrorInterface* error = nullptr;
+        Skip_t(socket_fd, length, &error);
+        err->reset(error);
+    }
+    MOCK_CONST_METHOD3(Skip_t, void(SocketDescriptor socket_fd, size_t length, ErrorInterface** err));
+
+    void CloseSocket(SocketDescriptor socket_fd, Error* err) const override {
+        ErrorInterface* error = nullptr;
+        CloseSocket_t(socket_fd, &error);
+        if(err) {
+            err->reset(error);
+        }
+    }
+    MOCK_CONST_METHOD2(CloseSocket_t, void(SocketDescriptor socket_fd, ErrorInterface** err));
+
+    FileDescriptor Open(const std::string& filename, int open_flags, Error* err) const override {
+        ErrorInterface* error = nullptr;
+        auto data = Open_t(filename, open_flags, &error);
         err->reset(error);
         return data;
     }
-    MOCK_CONST_METHOD2(ReadFileToString_t,
-                       std::string (const std::string& fname, SimpleError** err));
+    MOCK_CONST_METHOD3(Open_t, FileDescriptor(const std::string& filename, int open_flags, ErrorInterface** err));
 
-    MOCK_CONST_METHOD3(GetDataFromFile_t,
-                       uint8_t* (const std::string& fname, uint64_t fsize, SimpleError** err));
-    MOCK_CONST_METHOD2(FilesInFolder_t,
-                       FileInfos(
-                           const std::string& folder, hidra2::SimpleError
-                           ** err));
+    void Close(FileDescriptor fd, Error* err) const override {
+        ErrorInterface* error = nullptr;
+        Close_t(fd, &error);
+        if(err) {
+            err->reset(error);
+        };
+    }
+    MOCK_CONST_METHOD2(Close_t, void(FileDescriptor fd, ErrorInterface** err));
 
-    MOCK_CONST_METHOD3(read_t,
-                       int64_t(int
-                               __fd, void* buf, size_t
-                               count));
+    size_t Read(FileDescriptor fd, void* buf, size_t length, Error* err) const override {
+        ErrorInterface* error = nullptr;
+        auto data = Read_t(fd, buf, length, &error);
+        err->reset(error);
+        return data;
+    }
+    MOCK_CONST_METHOD4(Read_t, size_t(FileDescriptor fd, void* buf, size_t length, ErrorInterface** err));
 
-    MOCK_CONST_METHOD3(write_t,
-                       int64_t(int
-                               __fd,
-                               const void* __buf, size_t
-                               __n));
+    size_t Write(FileDescriptor fd, const void* buf, size_t length, Error* err) const override {
+        ErrorInterface* error = nullptr;
+        auto data = Write_t(fd, buf, length, &error);
+        err->reset(error);
+        return data;
+    }
+    MOCK_CONST_METHOD4(Write_t, size_t(FileDescriptor fd, const void* buf, size_t length, ErrorInterface** err));
 
-    MOCK_CONST_METHOD2(open_t,
-                       int(const char* __file, int __oflag));
+    void CreateNewDirectory(const std::string& directory_name, hidra2::Error* err) const override {
+        ErrorInterface* error = nullptr;
+        CreateNewDirectory_t(directory_name, &error);
+        err->reset(error);
+    }
+    MOCK_CONST_METHOD2(CreateNewDirectory_t, void(const std::string& directory_name, ErrorInterface** err));
 
-    MOCK_CONST_METHOD1(close_t,
-                       int(int __fd));
+    FileData GetDataFromFile(const std::string& fname, uint64_t fsize, Error* err) const override {
+        ErrorInterface* error = nullptr;
+        auto data = GetDataFromFile_t(fname, fsize, &error);
+        err->reset(error);
+        return FileData(data);
+    }
+
+    MOCK_CONST_METHOD3(GetDataFromFile_t, uint8_t* (const std::string& fname, uint64_t fsize, ErrorInterface** err));
+
+    Error WriteDataToFile(const std::string& fname, const FileData& data, size_t length) const override {
+        return Error{WriteDataToFile_t(fname, data.get(), length)};
+
+    }
+
+    MOCK_CONST_METHOD3(WriteDataToFile_t, ErrorInterface * (const std::string& fname, uint8_t* data, size_t fsize));
+
+    void CollectFileInformationRecursively(const std::string& path, std::vector<FileInfo>* files,
+                                           Error* err) const override {
+        ErrorInterface* error = nullptr;
+        CollectFileInformationRecursivly_t(path, files, &error);
+        err->reset(error);
+    }
+    MOCK_CONST_METHOD3(CollectFileInformationRecursivly_t, void(const std::string& path, std::vector<FileInfo>* files,
+                       ErrorInterface** err));
+
+    std::vector<FileInfo> FilesInFolder(const std::string& folder, Error* err) const override {
+        ErrorInterface* error = nullptr;
+        auto data = FilesInFolder_t(folder, &error);
+        err->reset(error);
+        return data;
+    }
+    MOCK_CONST_METHOD2(FilesInFolder_t, std::vector<FileInfo>(const std::string& folder, ErrorInterface** err));
+
+    std::string ReadFileToString(const std::string& fname, Error* err) const override {
+        ErrorInterface* error = nullptr;
+        auto data = ReadFileToString_t(fname, &error);
+        err->reset(error);
+        return data;
+    }
+    MOCK_CONST_METHOD2(ReadFileToString_t, std::string(const std::string& fname, ErrorInterface** err));
 };
 
 }
 
-#endif //HIDRA2_COMMON__MOCKIO_H
\ No newline at end of file
+#endif //HIDRA2_COMMON__MOCKIO_H
diff --git a/common/cpp/src/common/CMakeLists.txt b/common/cpp/src/common/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..40873cfcf7dba8ba3fd88b3246a20a05687b2fcb
--- /dev/null
+++ b/common/cpp/src/common/CMakeLists.txt
@@ -0,0 +1,7 @@
+set(TARGET_NAME common)
+
+set(TEST_SOURCE_FILES ../../unittests/common/test_error.cpp)
+
+set(TEST_LIBRARIES "${TARGET_NAME};system_io")
+include_directories(${HIDRA2_CXX_COMMON_INCLUDE_DIR})
+add_plain_unit_test(${TARGET_NAME} "${TEST_SOURCE_FILES}" "${TEST_LIBRARIES}")
diff --git a/common/cpp/src/json_parser/rapid_json.cpp b/common/cpp/src/json_parser/rapid_json.cpp
index e3f1f6ee55a9839476b3fe9eb2eb014fe61b137f..37d1c8771aa04d6f4150df97c229157ce6c10916 100644
--- a/common/cpp/src/json_parser/rapid_json.cpp
+++ b/common/cpp/src/json_parser/rapid_json.cpp
@@ -3,11 +3,12 @@
 
 using namespace rapidjson;
 
-#include "system_wrappers/system_io.h"
+#include "io/io_factory.h"
 
 namespace hidra2 {
 
-RapidJson::RapidJson(const std::string& json, bool read_from_file): io__{new SystemIO}, json_{json}, read_from_file_{read_from_file} {
+RapidJson::RapidJson(const std::string& json, bool read_from_file): io__{GenerateDefaultIO()}, json_{json},
+    read_from_file_{read_from_file} {
 
 }
 
diff --git a/common/cpp/src/json_parser/rapid_json.h b/common/cpp/src/json_parser/rapid_json.h
index 6f55934c2a159eb8746a1132669e6f58c0b31e70..ef26611e4abcafc3137fd18e7eef18ab07a717ee 100644
--- a/common/cpp/src/json_parser/rapid_json.h
+++ b/common/cpp/src/json_parser/rapid_json.h
@@ -3,7 +3,7 @@
 
 #include "rapidjson/document.h"
 #include "common/error.h"
-#include "system_wrappers/io.h"
+#include "io/io.h"
 
 
 namespace hidra2 {
diff --git a/common/cpp/src/system_io/CMakeLists.txt b/common/cpp/src/system_io/CMakeLists.txt
index 627606d1a12053ea62b8d9dacdc344ff06faa53d..274e3b7f7a9e17b3fe0c738d825b7ca7b1e44994 100644
--- a/common/cpp/src/system_io/CMakeLists.txt
+++ b/common/cpp/src/system_io/CMakeLists.txt
@@ -1,5 +1,6 @@
 set(TARGET_NAME system_io)
 set(SOURCE_FILES
+        io_factory.cpp
         system_io.cpp)
 IF(WIN32)
     set(SOURCE_FILES ${SOURCE_FILES} system_io_windows.cpp)
diff --git a/common/cpp/src/system_io/io_factory.cpp b/common/cpp/src/system_io/io_factory.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..de5e48a5d0a2e5dc345f47974e7a96adc36a8903
--- /dev/null
+++ b/common/cpp/src/system_io/io_factory.cpp
@@ -0,0 +1,13 @@
+#include "io/io_factory.h"
+
+#include "system_io.h"
+
+namespace hidra2 {
+
+IO* GenerateDefaultIO() {
+    return new SystemIO;
+}
+
+
+}
+
diff --git a/common/cpp/src/system_io/system_io.cpp b/common/cpp/src/system_io/system_io.cpp
index ef64b4b0a9eed38943a9f0321a2a5839552c3ddf..70c4a93ddfbbe4fd6c6872491370d2539e651ff5 100644
--- a/common/cpp/src/system_io/system_io.cpp
+++ b/common/cpp/src/system_io/system_io.cpp
@@ -6,53 +6,64 @@
 #include <cstring>
 #include <algorithm>
 
-#include <system_wrappers/system_io.h>
+
+#if defined(__linux__) || defined (__APPLE__)
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#endif
+
+#ifdef __APPLE__
+#include <sys/select.h>
+#endif
+
+#include "system_io.h"
 
 
 namespace hidra2 {
 
-Error IOErrorFromErrno() {
-    const char* message;
-    switch (errno) {
-    case 0:
-        return nullptr;
-    case ENOENT:
-    case ENOTDIR:
-        message = IOErrors::kFileNotFound;
-        break;
-    case EACCES:
-        message = IOErrors::kPermissionDenied;
-        break;
-    default:
-        message = IOErrors::kUnknownError;
-        break;
-    }
-    return TextError(message);
+const int SystemIO::kNetBufferSize = 1024 * 1024 ; //MiByte
+
+/*******************************************************************************
+ *                              system_io.cpp                                  *
+ * THIS FILE HOLDS GENERAL FUNCTIONS THAT CAN BE USED ON WINDOWS AND ON LINUX  *
+ *******************************************************************************/
+
+// PRIVATE FUNCTIONS - START
+
+void SortFileList(std::vector<FileInfo>* file_list) {
+    std::sort(file_list->begin(), file_list->end(),
+    [](FileInfo const & a, FileInfo const & b) {
+        return a.modify_date < b.modify_date;
+    });
 }
 
-uint64_t SystemIO::Read(int fd, uint8_t* array, uint64_t fsize, Error* err) const noexcept {
-    uint64_t totalbytes = 0;
-    int64_t readbytes = 0;
-    do {
-        readbytes = read(fd, array + totalbytes, fsize);
-        totalbytes += readbytes;
-    } while (readbytes > 0 && totalbytes < fsize);
+void StripBasePath(const std::string& folder, std::vector<FileInfo>* file_list) {
+    auto n_erase = folder.size() + 1;
+    for (auto& file : *file_list) {
+        file.name.erase(0, n_erase);
+    }
+}
 
-    if (totalbytes != fsize) {
-        *err = TextError(IOErrors::kReadError);
+void AssignIDs(FileInfos* file_list) {
+    int64_t id = 0;
+    for (auto& file : *file_list) {
+        file.id = ++id;
     }
-    return totalbytes;
 }
 
-int SystemIO::OpenFile(const std::string& fname, Error* err) const noexcept {
-    errno = 0;
-    int fd = open(fname.c_str(), O_RDONLY);
-    *err = IOErrorFromErrno();
-    if (*err != nullptr) {
-        (*err)->Append(fname);
-        return 0;
+std::unique_ptr<std::tuple<std::string, uint16_t>> SystemIO::SplitAddressToHostnameAndPort(std::string address) const {
+    try {
+        std::string host = address.substr(0, address.find(':'));
+
+        std::string port_str = address.substr(address.find(':') + 1, address.length());
+        uint16_t port = static_cast<uint16_t>(std::stoi(port_str));
+
+        return std::unique_ptr<std::tuple<std::string, uint16_t>>(new std::tuple<std::string, uint16_t>(host, port));
+    } catch (...) {
+        return nullptr;
     }
-    return fd;
 }
 
 uint8_t* AllocateArray(uint64_t fsize, Error* err) {
@@ -60,14 +71,17 @@ uint8_t* AllocateArray(uint64_t fsize, Error* err) {
     try {
         data_array = new uint8_t[fsize];
     } catch (...) {
-        *err = TextError(IOErrors::kMemoryAllocationError);
+        *err = ErrorTemplates::kMemoryAllocationError.Generate();
         return nullptr;
     }
     return data_array;
 }
 
-FileData SystemIO::GetDataFromFile(const std::string& fname, uint64_t fsize, Error* err) const noexcept {
-    auto fd = OpenFile(fname, err);
+// PRIVATE FUNCTIONS - END
+
+FileData SystemIO::GetDataFromFile(const std::string& fname, uint64_t fsize, Error* err) const {
+    *err = nullptr;
+    auto fd = Open(fname, IO_OPEN_MODE_READ, err);
     if (*err != nullptr) {
         return nullptr;
     }
@@ -79,40 +93,18 @@ FileData SystemIO::GetDataFromFile(const std::string& fname, uint64_t fsize, Err
 
     Read(fd, data_array, fsize, err);
     if (*err != nullptr) {
-        close(fd);
         (*err)->Append(fname);
+        Close(fd, nullptr);
         return nullptr;
     }
 
-    close(fd);
+    Close(fd, err);
     return FileData{data_array};
 }
 
-void SortFileList(FileInfos* file_list) {
-    std::sort(file_list->begin(), file_list->end(),
-    [](FileInfo const & a, FileInfo const & b) {
-        return a.modify_date < b.modify_date;
-    });
-}
-
-void StripBasePath(const std::string& folder, FileInfos* file_list) {
-    auto n_erase = folder.size() + 1;
-    for (auto& file : *file_list) {
-        file.name.erase(0, n_erase);
-    }
-}
-
-void AssignIDs(FileInfos* file_list) {
-    int64_t id = 0;
-    for (auto& file : *file_list) {
-        file.id = ++id;
-    }
-}
-
-
 FileInfos SystemIO::FilesInFolder(const std::string& folder, Error* err) const {
     FileInfos files{};
-    CollectFileInformationRecursivly(folder, &files, err);
+    CollectFileInformationRecursively(folder, &files, err);
     if (*err != nullptr) {
         return {};
     }
@@ -122,8 +114,33 @@ FileInfos SystemIO::FilesInFolder(const std::string& folder, Error* err) const {
     return files;
 }
 
-std::string SystemIO::ReadFileToString(const std::string& fname, Error* err)const noexcept {
-    auto info =  GetFileInfo(fname, err);
+void hidra2::SystemIO::CreateNewDirectory(const std::string& directory_name, Error* err) const {
+    if(_mkdir(directory_name.c_str()) == -1) {
+        *err = GetLastError();
+    } else {
+        *err = nullptr;
+    }
+}
+
+Error SystemIO::WriteDataToFile(const std::string& fname, const FileData& data, size_t length) const {
+    Error err;
+    auto fd = Open(fname, IO_OPEN_MODE_CREATE_AND_FAIL_IF_EXISTS | IO_OPEN_MODE_RW, &err);
+    if (err) {
+        return err;
+    }
+
+    Write(fd, data.get(), length, &err);
+    if (err) {
+        return err;
+    }
+
+    Close(fd, &err);
+    return err;
+}
+
+
+std::string SystemIO::ReadFileToString(const std::string& fname, Error* err) const {
+    auto info = GetFileInfo(fname, err);
     if (*err != nullptr) {
         return "";
     }
@@ -137,5 +154,389 @@ std::string SystemIO::ReadFileToString(const std::string& fname, Error* err)cons
 }
 
 
+std::unique_ptr<std::thread> SystemIO::NewThread(std::function<void()> function) const {
+    return std::unique_ptr<std::thread>(new std::thread(function));
+}
+
+void SystemIO::Skip(SocketDescriptor socket_fd, size_t length, Error* err) const {
+    static const size_t kSkipBufferSize = 1024;
+
+    //TODO need to find a better way to skip bytes
+    *err = nullptr;
+    std::unique_ptr<uint8_t[]> buffer;
+    try {
+        buffer.reset(new uint8_t[kSkipBufferSize]);
+    } catch(...) {
+        *err = ErrorTemplates::kMemoryAllocationError.Generate();
+        return;
+    }
+    size_t already_skipped = 0;
+    while(already_skipped < length) {
+        size_t need_to_skip = length - already_skipped;
+        if(need_to_skip > kSkipBufferSize)
+            need_to_skip = kSkipBufferSize;
+        size_t skipped_amount = Receive(socket_fd, buffer.get(), need_to_skip, err);
+        if(*err != nullptr) {
+            return;
+        }
+        already_skipped += skipped_amount;
+    }
+}
+
+hidra2::FileDescriptor hidra2::SystemIO::CreateAndConnectIPTCPSocket(const std::string& address,
+        Error* err) const {
+    *err = nullptr;
+
+    FileDescriptor fd = CreateSocket(AddressFamilies::INET, SocketTypes::STREAM, SocketProtocols::IP, err);
+    if(*err != nullptr) {
+        return -1;
+    }
+
+    InetConnect(fd, address, err);
+    if (*err != nullptr) {
+        CloseSocket(fd, nullptr);
+        return -1;
+    }
+
+    return fd;
+}
+
+int SystemIO::FileOpenModeToPosixFileOpenMode(int open_flags) const {
+    int flags = 0;
+    if((open_flags & IO_OPEN_MODE_READ && open_flags & IO_OPEN_MODE_WRITE) || open_flags & IO_OPEN_MODE_RW) {
+        flags |= O_RDWR;
+    } else {
+        if (open_flags & IO_OPEN_MODE_READ) {
+            flags |= O_RDONLY;
+        }
+        if (open_flags & IO_OPEN_MODE_WRITE) {
+            flags |= O_WRONLY;
+        }
+    }
+    if(open_flags & IO_OPEN_MODE_CREATE) {
+        flags |= O_CREAT;
+    }
+    if(open_flags & IO_OPEN_MODE_CREATE_AND_FAIL_IF_EXISTS) {
+        flags |= O_CREAT | O_EXCL;
+    }
+    if(open_flags & IO_OPEN_MODE_SET_LENGTH_0) {
+        flags |= O_TRUNC;
+    }
+    return flags;
+}
+
+std::string SystemIO::ResolveHostnameToIp(const std::string& hostname, Error* err) const {
+    InitializeSocketIfNecessary();
+    hostent* record = gethostbyname(hostname.c_str());
+    if (record == nullptr) {
+        *err = IOErrorTemplates::kUnableToResolveHostname.Generate();
+        return "";
+    }
+    in_addr* address = (in_addr*)(record->h_addr);
+    std::string ip_address = inet_ntoa(*address);
+
+    *err = nullptr;
+    return ip_address;
+}
+
+std::unique_ptr<sockaddr_in> SystemIO::BuildSockaddrIn(const std::string& address, Error* err) const {
+    auto hostname_port_tuple = SplitAddressToHostnameAndPort(address);
+    if (!hostname_port_tuple) {
+        *err = IOErrorTemplates::kInvalidAddressFormat.Generate();
+        return nullptr;
+    }
+    std::string host;
+    uint16_t port = 0;
+    std::tie(host, port) = *hostname_port_tuple;
+    host = ResolveHostnameToIp(host, err);
+    if(*err != nullptr) {
+        return nullptr;
+    }
+
+    short family = AddressFamilyToPosixFamily(AddressFamilies::INET);
+    if (family == -1) {
+        *err = IOErrorTemplates::kUnsupportedAddressFamily.Generate();
+        return nullptr;
+    }
 
-}
\ No newline at end of file
+    std::unique_ptr<sockaddr_in> socket_address = std::unique_ptr<sockaddr_in>(new sockaddr_in);
+    socket_address->sin_addr.s_addr = inet_addr(host.c_str());
+    socket_address->sin_port = htons(port);
+    socket_address->sin_family = family;
+
+    return socket_address;
+}
+
+void hidra2::SystemIO::InetConnect(SocketDescriptor socket_fd, const std::string& address, Error* err) const {
+    auto socket_address = BuildSockaddrIn(address, err);
+    if(*err != nullptr) {
+        return;
+    }
+
+    if (_connect(socket_fd, socket_address.get(), sizeof(sockaddr_in)) == -1) {
+        *err = GetLastError();
+        // On windows its normal that connect might give an "WSAEWOULDBLOCK" error,
+        // since the socket need time to be created
+        if (*err != nullptr && IOErrorTemplates::kResourceTemporarilyUnavailable != *err) {
+            return;
+        }
+    }
+    *err = nullptr;
+}
+
+std::unique_ptr<std::tuple<std::string, SocketDescriptor>> SystemIO::InetAcceptConnection(SocketDescriptor socket_fd,
+Error* err) const {
+    static short family = AddressFamilyToPosixFamily(AddressFamilies::INET);
+    if (family == -1) {
+        *err = IOErrorTemplates::kUnsupportedAddressFamily.Generate();
+        return nullptr;
+    }
+
+    sockaddr_in client_address{};
+    static size_t client_address_size = sizeof(sockaddr_in);
+
+    int peer_fd;
+    while (true) {
+        peer_fd = _accept(socket_fd, reinterpret_cast<sockaddr*>(&client_address), &client_address_size);
+
+        if (peer_fd == -1) {
+            *err = GetLastError();
+            if (*err != nullptr && IOErrorTemplates::kResourceTemporarilyUnavailable != *err) {
+                continue;
+            }
+            return nullptr;
+        }
+        break;
+    }
+
+    *err = nullptr;
+    ApplyNetworkOptions(peer_fd, err);
+
+    std::string
+    address = std::string(inet_ntoa(client_address.sin_addr)) + ':' + std::to_string(client_address.sin_port);
+    return std::unique_ptr<std::tuple<std::string, SocketDescriptor>>(new
+            std::tuple<std::string,
+            SocketDescriptor>(
+                address,
+                peer_fd));
+}
+
+hidra2::FileDescriptor hidra2::SystemIO::Open(const std::string& filename,
+                                              int open_flags,
+                                              Error* err) const {
+    int flags = FileOpenModeToPosixFileOpenMode(open_flags);
+    FileDescriptor fd = _open(filename.c_str(), flags);
+    if(fd == -1) {
+        *err = GetLastError();
+        (*err)->Append(filename);
+    } else {
+        *err = nullptr;
+    }
+    return fd;
+}
+
+void hidra2::SystemIO::CloseSocket(SocketDescriptor fd, Error* err) const {
+    if(err) {
+        *err = nullptr;
+    }
+    if(!_close_socket(fd) && err) {
+        *err = GetLastError();
+    }
+}
+
+void hidra2::SystemIO::Close(FileDescriptor fd, Error* err) const {
+    if(err) {
+        *err = nullptr;
+    }
+    if(!_close(fd) && err) {
+        *err = GetLastError();
+    }
+}
+
+short hidra2::SystemIO::AddressFamilyToPosixFamily(AddressFamilies address_family) const {
+    switch (address_family) {
+    case AddressFamilies::INET:
+        return AF_INET;
+    }
+    return -1;
+}
+
+int hidra2::SystemIO::SocketTypeToPosixType(SocketTypes socket_type) const {
+    switch (socket_type) {
+    case SocketTypes::STREAM:
+        return SOCK_STREAM;
+    }
+    return -1;
+}
+
+int hidra2::SystemIO::SocketProtocolToPosixProtocol(SocketProtocols socket_protocol) const {
+    switch (socket_protocol) {
+    case SocketProtocols::IP:
+        return IPPROTO_IP;
+    }
+    return -1;
+}
+
+SocketDescriptor SystemIO::CreateSocket(AddressFamilies address_family,
+                                        SocketTypes socket_type,
+                                        SocketProtocols socket_protocol,
+                                        Error* err) const {
+    int domain = AddressFamilyToPosixFamily(address_family);
+    if(domain == -1) {
+        *err = IOErrorTemplates::kUnsupportedAddressFamily.Generate();
+        return -1;
+    }
+
+    int type = SocketTypeToPosixType(socket_type);
+    if(type == -1) {
+        *err = IOErrorTemplates::kUnknownIOError.Generate();
+        return -1;
+    }
+
+    int protocol = SocketProtocolToPosixProtocol(socket_protocol);
+    if(protocol == -1) {
+        *err = IOErrorTemplates::kUnknownIOError.Generate();
+        return -1;
+    }
+
+    SocketDescriptor socket_fd = _socket(domain, type, protocol);
+    if(socket_fd == -1) {
+        *err = GetLastError();
+        return socket_fd;
+    }
+
+    *err = nullptr;
+
+    ApplyNetworkOptions(socket_fd, err);
+
+    return socket_fd;
+}
+
+void hidra2::SystemIO::InetBind(SocketDescriptor socket_fd, const std::string& address,
+                                Error* err) const {
+    *err = nullptr;
+
+    int family = AddressFamilyToPosixFamily(AddressFamilies::INET);
+    if (family == -1) {
+        *err = IOErrorTemplates::kUnsupportedAddressFamily.Generate();
+        return;
+    }
+
+    auto socket_address = BuildSockaddrIn(address, err);
+    if(*err != nullptr) {
+        return;
+    }
+
+    if (::bind(socket_fd, reinterpret_cast<const sockaddr*>(socket_address.get()), sizeof(sockaddr_in)) == -1) {
+        *err = GetLastError();
+    }
+}
+
+void hidra2::SystemIO::Listen(SocketDescriptor socket_fd, int backlog, Error* err) const {
+    *err = nullptr;
+
+    if (_listen(socket_fd, backlog) == -1) {
+        *err = GetLastError();
+    }
+}
+
+SocketDescriptor SystemIO::CreateAndBindIPTCPSocketListener(const std::string& address, int backlog, Error* err) const {
+    FileDescriptor listener_fd = CreateSocket(AddressFamilies::INET, SocketTypes::STREAM, SocketProtocols::IP, err);
+
+    if(*err) {
+        return -1;
+    }
+
+    InetBind(listener_fd, address, err);
+    if(*err) {
+        CloseSocket(listener_fd, nullptr);
+        return -1;
+    }
+
+    Listen(listener_fd, backlog, err);
+    if(*err) {
+        CloseSocket(listener_fd, nullptr);
+        return -1;
+    }
+
+    return listener_fd;
+}
+
+size_t hidra2::SystemIO::ReceiveWithTimeout(SocketDescriptor socket_fd, void* buf, size_t length, long timeout_in_usec,
+                                            Error* err) const {
+    *err = nullptr;
+
+    fd_set read_fds;
+    FD_ZERO(&read_fds);
+    FD_SET(socket_fd, &read_fds);
+    timeval timeout;
+    timeout.tv_sec = 0;
+    timeout.tv_usec = timeout_in_usec;
+
+    int res = ::select(socket_fd + 1, &read_fds, nullptr, nullptr, &timeout);
+    if (res == 0) {
+        *err = IOErrorTemplates::kTimeout.Generate();
+        return 0;
+    }
+    if (res == -1) {
+        *err = GetLastError();
+        return 0;
+    }
+
+    return Receive(socket_fd, buf, length, err);
+}
+
+
+size_t hidra2::SystemIO::Read(FileDescriptor fd, void* buf, size_t length, Error* err) const {
+    return Transfer(_read, fd, buf, length, err);
+}
+
+size_t hidra2::SystemIO::Write(FileDescriptor fd, const void* buf, size_t length, Error* err) const {
+    return Transfer(_write, fd, buf, length, err);
+}
+
+size_t hidra2::SystemIO::Receive(SocketDescriptor socket_fd, void* buf, size_t length, Error* err) const {
+    return Transfer(_recv, socket_fd, buf, length, err);
+}
+
+size_t hidra2::SystemIO::Send(SocketDescriptor socket_fd, const void* buf, size_t length, Error* err) const {
+    return Transfer(_send, socket_fd, buf, length, err);
+}
+
+size_t SystemIO::Transfer(ssize_t (* method)(FileDescriptor, const void*, size_t),
+                          FileDescriptor fd,
+                          const void* buf,
+                          size_t length,
+                          Error* err) const {
+    return Transfer(reinterpret_cast<ssize_t (*)(FileDescriptor, void*, size_t)>(method), fd,
+                    const_cast<void*>(buf), length, err);
+}
+
+size_t SystemIO::Transfer(ssize_t (* method)(FileDescriptor, void*, size_t), FileDescriptor fd, void* buf,
+                          size_t length, Error* err) const {
+    *err = nullptr;
+    size_t already_transferred = 0;
+
+    while (already_transferred < length) {
+        ssize_t received_amount = method(fd, (uint8_t*) buf + already_transferred, length - already_transferred);
+        if (received_amount == 0) {
+            *err = ErrorTemplates::kEndOfFile.Generate();
+            return already_transferred;
+        }
+        if (received_amount == -1) {
+            *err = GetLastError();
+            if(IOErrorTemplates::kResourceTemporarilyUnavailable == *err) {
+                continue;
+            }
+            if(*err == nullptr) {
+                *err = IOErrorTemplates::kUnknownIOError.Generate();
+            }
+            return already_transferred;//Return the amount of _ensured_ transferred bytes
+        }
+        already_transferred += received_amount;
+    }
+    *err = nullptr;
+    return already_transferred;
+}
+
+}
diff --git a/common/cpp/src/system_io/system_io.h b/common/cpp/src/system_io/system_io.h
new file mode 100644
index 0000000000000000000000000000000000000000..5fb98136244570c99fa71e4ec23728eddd68c222
--- /dev/null
+++ b/common/cpp/src/system_io/system_io.h
@@ -0,0 +1,111 @@
+#ifndef HIDRA2_SYSTEM__SYSTEM_IO_H
+#define HIDRA2_SYSTEM__SYSTEM_IO_H
+
+#include "../../include/io/io.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#undef GetObject
+#undef max
+#undef min
+typedef SSIZE_T ssize_t;
+#endif
+
+#if defined(__linux__) || defined (__APPLE__)
+#include "../../../../../../../../usr/include/netinet/in.h"
+#endif
+
+namespace hidra2 {
+
+class SystemIO final : public IO {
+  private:
+    static const int kNetBufferSize;//TODO: need to set by config
+
+    void ApplyNetworkOptions(SocketDescriptor socket_fd, Error* err) const;
+
+    //void CollectFileInformationRecursively(const std::string& path, std::vector<FileInfo>* files, IOErrors* err) const;
+    int FileOpenModeToPosixFileOpenMode(int open_flags) const;
+    Error GetLastError() const;
+
+    short AddressFamilyToPosixFamily      (AddressFamilies address_family) const;
+    int SocketTypeToPosixType           (SocketTypes socket_type) const;
+    int SocketProtocolToPosixProtocol   (SocketProtocols socket_protocol) const;
+
+    // System function mapping. Should only be called by the wrapper function
+    FileDescriptor  _open(const char* filename, int posix_open_flags) const;
+    bool            _close(FileDescriptor fd) const;
+    int             _mkdir(const char* dirname) const;
+
+    SocketDescriptor	_socket(int address_family, int socket_type, int socket_protocol) const;
+    SocketDescriptor	_connect(SocketDescriptor socket_fd, const void* address, size_t address_length) const;
+    int					_listen(SocketDescriptor socket_fd, int backlog) const;
+    SocketDescriptor	_accept(SocketDescriptor socket_fd, void* address, size_t* address_length) const;
+    bool			    _close_socket(SocketDescriptor socket_fd) const;
+
+    void                                                InitializeSocketIfNecessary() const;
+    std::unique_ptr<std::tuple<std::string, uint16_t>>  SplitAddressToHostnameAndPort(std::string address) const;
+
+    FileInfo GetFileInfo(const std::string& name, Error* err) const;
+
+    std::unique_ptr<sockaddr_in> BuildSockaddrIn(const std::string& address, Error* err) const;
+
+    /*
+     * Transfer functions
+     */
+    size_t Transfer(ssize_t (*method)(FileDescriptor, const void*, size_t), FileDescriptor fd, const void* buf,
+                    size_t length,
+                    Error* err) const;
+    size_t Transfer(ssize_t (*method)(FileDescriptor, void*, size_t), FileDescriptor fd, void* buf, size_t length,
+                    Error* err) const;
+    static ssize_t	    _send(SocketDescriptor socket_fd, const void* buffer, size_t length);
+    static ssize_t		_recv(SocketDescriptor socket_fd, void* buffer, size_t length);
+    static ssize_t      _read(FileDescriptor fd, void* buffer, size_t length);
+    static ssize_t      _write(FileDescriptor fd, const void* buffer, size_t count);
+
+  public:
+    /*
+     * Special
+     */
+    std::unique_ptr<std::thread>    NewThread(std::function<void()> function) const;
+
+
+    // this is not standard function - to be implemented differently in windows and linux
+    std::vector<FileInfo>   FilesInFolder(const std::string& folder, Error* err) const;
+
+    /*
+     * Network
+     */
+    SocketDescriptor  CreateSocket(AddressFamilies address_family, SocketTypes socket_type, SocketProtocols socket_protocol,
+                                   Error* err) const;
+    void            Listen(SocketDescriptor socket_fd, int backlog, Error* err) const;
+    void            InetBind(SocketDescriptor socket_fd, const std::string& address, Error* err) const;
+    SocketDescriptor  CreateAndBindIPTCPSocketListener(const std::string& address, int backlog, Error* err) const;
+    std::unique_ptr<std::tuple<std::string, SocketDescriptor>> InetAcceptConnection(SocketDescriptor socket_fd,
+            Error* err) const;
+    std::string     ResolveHostnameToIp(const std::string& hostname, Error* err) const;
+    void            InetConnect(SocketDescriptor socket_fd, const std::string& address, Error* err) const;
+    SocketDescriptor  CreateAndConnectIPTCPSocket(const std::string& address, Error* err) const;
+    size_t          Receive(SocketDescriptor socket_fd, void* buf, size_t length, Error* err) const;
+    size_t          ReceiveWithTimeout(SocketDescriptor socket_fd, void* buf, size_t length, long timeout_in_usec,
+                                       Error* err) const;
+    size_t          Send(SocketDescriptor socket_fd, const void* buf, size_t length, Error* err) const;
+    void            Skip(SocketDescriptor socket_fd, size_t length, Error* err) const;
+    void            CloseSocket(SocketDescriptor socket_fd, Error* err) const;
+
+    /*
+     * Filesystem
+     */
+    FileDescriptor  Open(const std::string& filename, int open_flags, Error* err) const;
+    void            Close(FileDescriptor fd, Error* err) const;
+    size_t          Read(FileDescriptor fd, void* buf, size_t length, Error* err) const;
+    size_t          Write(FileDescriptor fd, const void* buf, size_t length, Error* err) const;
+    void            CreateNewDirectory(const std::string& directory_name, Error* err) const;
+    FileData        GetDataFromFile(const std::string& fname, uint64_t fsize, Error* err) const;
+    Error           WriteDataToFile  (const std::string& fname, const FileData& data, size_t length) const;
+    void            CollectFileInformationRecursively(const std::string& path, std::vector<FileInfo>* files,
+                                                      Error* err) const;
+    std::string     ReadFileToString(const std::string& fname, Error* err) const;
+};
+}
+
+#endif //HIDRA2_SYSTEM__SYSTEM_IO_H
diff --git a/common/cpp/src/system_io/system_io_linux.cpp b/common/cpp/src/system_io/system_io_linux.cpp
index 9a3653f285f97a99b455d0ef313115fa45b6325d..e0faf78b744ddc6becc4e556d2d575ec9e6fdcf6 100644
--- a/common/cpp/src/system_io/system_io_linux.cpp
+++ b/common/cpp/src/system_io/system_io_linux.cpp
@@ -1,15 +1,18 @@
-#include "system_wrappers/system_io.h"
 
 #include <cstring>
 
 #include <dirent.h>
 #include <sys/stat.h>
 #include <algorithm>
-
+#include <netinet/in.h>
+#include <arpa/inet.h>
 #include <fcntl.h>
+#include <iostream>
+#include <zconf.h>
+#include <netdb.h>
+
+#include "system_io.h"
 
-#include <cerrno>
-#include <unistd.h>
 
 using std::string;
 using std::vector;
@@ -17,6 +20,56 @@ using std::chrono::system_clock;
 
 namespace hidra2 {
 
+/**
+ * \defgroup SYSTEM_IO_LINUX_PRIVATE
+ * Local and private function that are being used by system_io_linux.cpp
+ * @{
+ */
+
+Error GetLastErrorFromErrno() {
+    switch (errno) {
+    case 0:
+        return nullptr;
+    case EBADF:
+        return IOErrorTemplates::kBadFileNumber.Generate();
+    case EAGAIN:
+        return IOErrorTemplates::kResourceTemporarilyUnavailable.Generate();
+    case ENOENT:
+    case ENOTDIR:
+        return IOErrorTemplates::kFileNotFound.Generate();
+    case EACCES:
+        return IOErrorTemplates::kPermissionDenied.Generate();
+    case EFAULT:
+        return IOErrorTemplates::kInvalidMemoryAddress.Generate();
+    case EEXIST:
+        return IOErrorTemplates::kFileAlreadyExists.Generate();
+    case ENOSPC:
+        return IOErrorTemplates::kNoSpaceLeft.Generate();
+    case ECONNREFUSED:
+        return IOErrorTemplates::kConnectionRefused.Generate();
+    case EADDRINUSE:
+        return IOErrorTemplates::kAddressAlreadyInUse.Generate();
+    case ECONNRESET:
+        return IOErrorTemplates::kConnectionResetByPeer.Generate();
+    case ENOTSOCK:
+        return IOErrorTemplates::kSocketOperationOnNonSocket.Generate();
+    case ENOPROTOOPT:
+        return IOErrorTemplates::kSocketOperationUnknownAtLevel.Generate();
+    case EDOM:
+        return IOErrorTemplates::kSocketOperationValueOutOfBound.Generate();
+
+    default:
+        std::cout << "[IOErrorsFromErrno] Unknown error code: " << errno << std::endl;
+        Error err = IOErrorTemplates::kUnknownIOError.Generate();
+        (*err).Append("Unknown error code: " + std::to_string(errno));
+        return err;
+    }
+};
+
+Error SystemIO::GetLastError() const {
+    return GetLastErrorFromErrno();
+}
+
 bool IsDirectory(const struct dirent* entity) {
     return entity->d_type == DT_DIR &&
            strstr(entity->d_name, "..") == nullptr &&
@@ -50,12 +103,12 @@ struct stat FileStat(const string& fname, Error* err) {
     errno = 0;
     int res = stat(fname.c_str(), &t_stat);
     if (res < 0) {
-        *err = IOErrorFromErrno();
+        *err = GetLastErrorFromErrno();
     }
     return t_stat;
 }
 
-FileInfo GetFileInfo(const string& name, Error* err)  {
+FileInfo GetFileInfo(const string& name, Error* err) {
     FileInfo file_info;
 
     SetFileName(name, &file_info);
@@ -73,6 +126,10 @@ FileInfo GetFileInfo(const string& name, Error* err)  {
     return file_info;
 }
 
+FileInfo SystemIO::GetFileInfo(const string& name, Error* err) const {
+    return ::hidra2::GetFileInfo(name, err);
+}
+
 void ProcessFileEntity(const struct dirent* entity, const std::string& path,
                        FileInfos* files, Error* err)  {
 
@@ -88,24 +145,22 @@ void ProcessFileEntity(const struct dirent* entity, const std::string& path,
     files->push_back(file_info);
 }
 
-void SystemIO::CollectFileInformationRecursivly(const std::string& path,
-                                                FileInfos* files, Error* err)  const {
+/** @} */
+
+void SystemIO::CollectFileInformationRecursively(const std::string& path,
+                                                 FileInfos* files, Error* err)  const {
     errno = 0;
     auto dir = opendir((path).c_str());
     if (dir == nullptr) {
-        *err = IOErrorFromErrno();
+        *err = GetLastError();
         (*err)->Append(path);
         return;
     }
-    while (true) {
-        errno = 0;
-        struct dirent* current_entity = readdir(dir);
-        if (!current_entity) {
-            break;
-        }
+
+    while (struct dirent* current_entity = readdir(dir)) {
         if (IsDirectory(current_entity)) {
-            CollectFileInformationRecursivly(path + "/" + current_entity->d_name,
-                                             files, err);
+            CollectFileInformationRecursively(path + "/" + current_entity->d_name,
+                                              files, err);
         } else {
             ProcessFileEntity(current_entity, path, files, err);
         }
@@ -115,26 +170,77 @@ void SystemIO::CollectFileInformationRecursivly(const std::string& path,
             return;
         }
     }
-    *err = IOErrorFromErrno();
+    *err = GetLastError();
     closedir(dir);
 }
 
+void SystemIO::ApplyNetworkOptions(SocketDescriptor socket_fd, Error* err) const {
+    //TODO: Need to change network layer code, so everything can be NonBlocking
+    // in use and one have to wait for some time until the system cleans up the stuff
+    int flag;
+    if (
+        /*(flags = fcntl(socket_fd, F_GETFL, 0)) == -1
+        ||
+        fcntl(socket_fd, F_SETFL, flags | O_NONBLOCK) == -1
+        ||*/
+        setsockopt(socket_fd, SOL_SOCKET, SO_SNDBUF, (char*)&kNetBufferSize, sizeof(kNetBufferSize)) != 0
+        ||
+        setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(int)) != 0
+    ) {
+        *err = GetLastError();
+    }
+}
+
+FileDescriptor SystemIO::_open(const char* filename, int posix_open_flags) const {
+    return ::open(filename, posix_open_flags, S_IWUSR | S_IRWXU);
+}
 
-int64_t SystemIO::read(int __fd, void* buf, size_t count) const noexcept {
-    return (int64_t) ::read(__fd, buf, count);
+bool SystemIO::_close(hidra2::FileDescriptor fd) const {
+    return ::close(fd) == 0;
 }
 
-int64_t SystemIO::write(int __fd, const void* __buf, size_t __n) const noexcept {
-    return (int64_t) ::write(__fd, __buf, __n);
+ssize_t SystemIO::_read(hidra2::FileDescriptor fd, void* buffer, size_t length) {
+    return ::read(fd, buffer, length);
 }
 
-int SystemIO::open(const char* __file, int __oflag) const noexcept {
-    return ::open(__file, __oflag);
+ssize_t SystemIO::_write(hidra2::FileDescriptor fd, const void* buffer, size_t length) {
+    return ::write(fd, buffer, length);
 }
 
-int SystemIO::close(int __fd) const noexcept {
-    return ::close(__fd);
+SocketDescriptor SystemIO::_socket(int address_family, int socket_type, int socket_protocol) const {
+    return ::socket(address_family, socket_type, socket_protocol);
 }
 
+ssize_t SystemIO::_send(SocketDescriptor socket_fd, const void* buffer, size_t length) {
+    return ::send(socket_fd, buffer, length, MSG_DONTWAIT);
+}
+
+ssize_t SystemIO::_recv(SocketDescriptor socket_fd, void* buffer, size_t length) {
+    return ::recv(socket_fd, buffer, length, MSG_DONTWAIT);
+}
+
+int SystemIO::_mkdir(const char* dirname) const {
+    return ::mkdir(dirname, S_IRWXU);
+}
+
+int SystemIO::_listen(SocketDescriptor socket_fd, int backlog) const {
+    return ::listen(socket_fd, backlog);
+}
+
+SocketDescriptor SystemIO::_connect(SocketDescriptor socket_fd, const void* address, size_t address_length) const {
+    return ::connect(socket_fd, static_cast<const sockaddr*>(address), static_cast<socklen_t>(address_length));
+}
+
+SocketDescriptor SystemIO::_accept(SocketDescriptor socket_fd, void* address, size_t* address_length) const {
+    return ::accept(socket_fd, static_cast<sockaddr*>(address), reinterpret_cast<socklen_t*>(address_length));
+}
+
+bool SystemIO::_close_socket(SocketDescriptor socket_fd) const {
+    return ::close(socket_fd) == 0;
+}
+
+void SystemIO::InitializeSocketIfNecessary() const {
+
+}
 
 }
diff --git a/common/cpp/src/system_io/system_io_windows.cpp b/common/cpp/src/system_io/system_io_windows.cpp
index 19be8a1509bf07e4b1e82d935a5362564234aef6..de37715511c647da449d85c7649a0c96560157d4 100644
--- a/common/cpp/src/system_io/system_io_windows.cpp
+++ b/common/cpp/src/system_io/system_io_windows.cpp
@@ -1,12 +1,13 @@
-#include "system_wrappers/system_io.h"
+#include "system/system_io.h"
 
 #include <cstring>
 #include <sys/stat.h>
 #include <algorithm>
 #include <io.h>
 #include <windows.h>
-
 #include <fcntl.h>
+#include <iostream>
+#include <direct.h>
 
 
 using std::string;
@@ -16,26 +17,45 @@ using std::chrono::system_clock;
 namespace hidra2 {
 
 Error IOErrorFromGetLastError() {
-    const char* message;
-    switch (GetLastError()) {
-    case ERROR_SUCCESS :
+    DWORD last_error = GetLastError();
+    switch (last_error) {
+    case ERROR_SUCCESS:
         return nullptr;
     case ERROR_PATH_NOT_FOUND:
     case ERROR_FILE_NOT_FOUND:
-        message = IOErrors::kFileNotFound;
-        break;
+        return IOErrorTemplates::kFileNotFound.Generate();
     case ERROR_ACCESS_DENIED:
-        message = IOErrors::kPermissionDenied;
-        break;
+        return IOErrorTemplates::kPermissionDenied.Generate();
+    case ERROR_CONNECTION_REFUSED:
+        return IOErrorTemplates::kConnectionRefused.Generate();
+    case WSAEFAULT:
+        return IOErrorTemplates::kInvalidMemoryAddress.Generate();
+    case WSAECONNRESET:
+        return IOErrorTemplates::kConnectionResetByPeer.Generate();
+    case WSAENOTSOCK:
+        return IOErrorTemplates::kSocketOperationOnNonSocket.Generate();
+    case WSAEWOULDBLOCK:
+        return IOErrorTemplates::kResourceTemporarilyUnavailable.Generate();
+    case WSAEADDRNOTAVAIL:
+        return IOErrorTemplates::kAddressNotValid.Generate();
+    case WSAECONNREFUSED:
+        return IOErrorTemplates::kConnectionRefused.Generate();
+    case ERROR_FILE_EXISTS:
+        return IOErrorTemplates::kFileAlreadyExists.Generate();
     default:
-        message = IOErrors::kUnknownError;
-        break;
+        std::cout << "[IOErrorFromGetLastError] Unknown error code: " << last_error << std::endl;
+        Error err = IOErrorTemplates::kUnknownIOError.Generate();
+        (*err).Append("Unknown error code: " + std::to_string(last_error));
+        return err;
     }
-    return TextError(message);
+}
+
+Error SystemIO::GetLastError() const {
+    return IOErrorFromGetLastError();
 }
 
 Error CheckFileTime(const FILETIME& ft) {
-    SYSTEMTIME st = {0};
+    SYSTEMTIME st = { 0 };
     if (!FileTimeToSystemTime(&ft, &st)) {
         return IOErrorFromGetLastError();
     }
@@ -85,7 +105,7 @@ bool IsDirectory(const WIN32_FIND_DATA f) {
            strstr(f.cFileName, ".") == nullptr;
 }
 
-FileInfo GetFileInfo_win(const WIN32_FIND_DATA& f, const string& name, Error* err)  {
+FileInfo GetFileInfo_win(const WIN32_FIND_DATA& f, const string& name, Error* err) {
     FileInfo file_info;
 
     file_info.modify_date = FileTime2TimePoint(f.ftLastWriteTime, err);
@@ -105,10 +125,10 @@ FileInfo GetFileInfo_win(const WIN32_FIND_DATA& f, const string& name, Error* er
 }
 
 
-FileInfo GetFileInfo(const string& name, Error* err) {
+FileInfo SystemIO::GetFileInfo(const std::string& name, Error* err) const {
     WIN32_FIND_DATA f;
 
-    auto hFind = FindFirstFile(name.c_str() , &f);
+    auto hFind = FindFirstFile(name.c_str(), &f);
     if (hFind == INVALID_HANDLE_VALUE) {
         *err = IOErrorFromGetLastError();
         (*err)->Append(name);
@@ -118,7 +138,6 @@ FileInfo GetFileInfo(const string& name, Error* err) {
     return GetFileInfo_win(f, name, err);
 }
 
-
 void ProcessFileEntity(const WIN32_FIND_DATA& f, const std::string& path,
                        FileInfos* files, Error* err) {
 
@@ -135,9 +154,8 @@ void ProcessFileEntity(const WIN32_FIND_DATA& f, const std::string& path,
     files->push_back(file_info);
 }
 
-
-void SystemIO::CollectFileInformationRecursivly(const std::string& path,
-                                                FileInfos* files, Error* err) const {
+void SystemIO::CollectFileInformationRecursively(const std::string& path,
+                                                 FileInfos* files, Error* err) const {
     WIN32_FIND_DATA find_data;
     HANDLE handle = FindFirstFile((path + "\\*.*").c_str(), &find_data);
     if (handle == INVALID_HANDLE_VALUE) {
@@ -148,7 +166,7 @@ void SystemIO::CollectFileInformationRecursivly(const std::string& path,
 
     do {
         if (IsDirectory(find_data)) {
-            CollectFileInformationRecursivly(path + "\\" + find_data.cFileName, files, err);
+            CollectFileInformationRecursively(path + "\\" + find_data.cFileName, files, err);
         } else {
             ProcessFileEntity(find_data, path, files, err);
         }
@@ -163,25 +181,95 @@ void SystemIO::CollectFileInformationRecursivly(const std::string& path,
     } else {
         *err = IOErrorFromGetLastError();
     }
-}
 
-int64_t SystemIO::read(int __fd, void* buf, size_t count) const noexcept {
-    return (int64_t) _read(__fd, buf, (unsigned int) count);
 }
 
-int64_t SystemIO::write(int __fd, const void* __buf, size_t __n) const noexcept {
-    return (int64_t) _write(__fd, __buf, (unsigned int) __n);
+void hidra2::SystemIO::ApplyNetworkOptions(SocketDescriptor socket_fd, Error* err) const {
+    //TODO: Seeing issues when using these settings - need further investigation
+    //Event if NonBlockingIO is set, it seems that _recv is a blocking call :/
+    /*
+    static u_long iMode = 1;
+
+    if (
+    	ioctlsocket(socket_fd, FIONBIO, &iMode) != 0
+    	||
+    	setsockopt(socket_fd, SOL_SOCKET, SO_SNDBUF, (char*)&kNetBufferSize, sizeof(kNetBufferSize)) != 0
+    	||
+    	setsockopt(socket_fd, SOL_SOCKET, SO_SNDBUF, (char*)&kNetBufferSize, sizeof(kNetBufferSize)) != 0
+    	) {
+    	*err = GetLastError();
+    }
+    */
 }
 
-int SystemIO::open(const char* __file, int __oflag) const noexcept {
+FileDescriptor SystemIO::_open(const char* filename, int posix_open_flags) const {
     int fd;
-    errno = _sopen_s(&fd, __file, __oflag | _O_BINARY, _SH_DENYNO, _S_IREAD | _S_IWRITE);
+    errno = _sopen_s(&fd, filename, posix_open_flags | _O_BINARY, _SH_DENYNO, _S_IREAD | _S_IWRITE);
     return fd;
 }
 
-int SystemIO::close(int __fd) const noexcept {
-    return ::_close(__fd);
+bool SystemIO::_close(FileDescriptor fd) const {
+    return ::_close(fd) == 0;
+}
+
+bool SystemIO::_close_socket(SocketDescriptor fd) const {
+    return ::closesocket(fd) == 0;
+}
+
+SocketDescriptor SystemIO::_socket(int address_family, int socket_type, int socket_protocol) const {
+    InitializeSocketIfNecessary();
+    return ::socket(address_family, socket_type, socket_protocol);
+}
+
+SocketDescriptor SystemIO::_connect(SocketDescriptor socket_fd, const void* address, size_t address_length) const {
+    return ::connect(socket_fd, static_cast<const sockaddr*>(address), address_length);
+}
+
+ssize_t SystemIO::_read(FileDescriptor fd, void* buffer, size_t length) {
+    return ::_read(fd, (char*)buffer, length);
 }
 
+ssize_t SystemIO::_write(FileDescriptor fd, const void* buffer, size_t length) {
+    return ::_write(fd, (const char*)buffer, length);
+}
+
+ssize_t SystemIO::_send(SocketDescriptor socket_fd, const void* buffer, size_t length) {
+    return ::send(socket_fd, (char*)buffer, length, 0);
+}
+
+ssize_t SystemIO::_recv(SocketDescriptor socket_fd, void* buffer, size_t length) {
+    return ::recv(socket_fd, (char*)buffer, length, 0);
+}
+
+int SystemIO::_mkdir(const char* dirname) const {
+    return ::_mkdir(dirname);
+}
+
+int SystemIO::_listen(SocketDescriptor fd, int backlog) const {
+    return ::listen(fd, backlog);
+}
+
+SocketDescriptor SystemIO::_accept(SocketDescriptor socket_fd, void* address, size_t* address_length) const {
+    return ::accept(socket_fd, static_cast<sockaddr*>(address), (int*)address_length);
+}
+
+void SystemIO::InitializeSocketIfNecessary() const {
+    static bool WSAStartupDone = false;
+    if (!WSAStartupDone) {
+        WSAStartupDone = true;
+        WORD wVersionRequested = MAKEWORD(2, 2);
+        WSADATA wsaData;
+        int err = WSAStartup(wVersionRequested, &wsaData);
+        if (err != 0) {
+            std::cout << "[_socket/WSAStartup] Failed to WSAStartup with version 2.2" << std::endl;
+            WSACleanup();
+            // Do not return, since ::socket has to set an errno
+        } else {
+            std::atexit([] {
+                WSACleanup();
+            });
+        }
+    }
+}
 
 }
diff --git a/common/cpp/unittests/common/test_error.cpp b/common/cpp/unittests/common/test_error.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9055fb3ef7b6b9f8914bba43f45e3e39938ba052
--- /dev/null
+++ b/common/cpp/unittests/common/test_error.cpp
@@ -0,0 +1,26 @@
+#include <gmock/gmock.h>
+#include <common/error.h>
+#include "gtest/gtest.h"
+
+using hidra2::Error;
+using ::testing::Eq;
+using ::testing::Ne;
+
+namespace {
+
+TEST(ErrorTemplate, GenerateNoNullptr) {
+    Error error = hidra2::ErrorTemplates::kEndOfFile.Generate();
+    ASSERT_THAT(error, Ne(nullptr));
+}
+
+TEST(ErrorTemplate, EqCheck) {
+    Error error = hidra2::ErrorTemplates::kEndOfFile.Generate();
+    ASSERT_TRUE(hidra2::ErrorTemplates::kEndOfFile == error);
+}
+
+
+TEST(ErrorTemplate, NeCheck) {
+    Error error = hidra2::ErrorTemplates::kEndOfFile.Generate();
+    ASSERT_FALSE(hidra2::ErrorTemplates::kMemoryAllocationError == error);
+}
+}
diff --git a/common/cpp/unittests/json_parser/test_json_parser.cpp b/common/cpp/unittests/json_parser/test_json_parser.cpp
index d4545a5a0129152ee7b03099cab941113db5be53..0767fd02065553e54cafbc86556183eb40702eec 100644
--- a/common/cpp/unittests/json_parser/test_json_parser.cpp
+++ b/common/cpp/unittests/json_parser/test_json_parser.cpp
@@ -73,7 +73,6 @@ TEST(ParseString, DoubleEmbeddedConvertToJson) {
     ASSERT_THAT(id, Eq(2));
 }
 
-
 TEST(ParseString, ErrorOnWrongEmbeddedKey) {
     std::string json = R"({"id1":{"test":2}})";
 
@@ -98,7 +97,6 @@ TEST(ParseString, ErrorOnWrongEmbeddedSubKey) {
     ASSERT_THAT(err->Explain(), ::testing::HasSubstr("cannot find"));
 }
 
-
 TEST(ParseString, ErrorOnWrongKey) {
     std::string json = R"({"_id":"2"})";
 
@@ -150,7 +148,6 @@ TEST(ParseString, IntArrayConvertToJson) {
     ASSERT_THAT(vec, ElementsAre(1, 2, 3));
 }
 
-
 TEST(ParseString, IntArrayErrorConvertToJson) {
     std::string json = R"({"array":[1,2,"3"]})";
 
@@ -176,7 +173,6 @@ TEST(ParseString, StringArrayConvertToJson) {
     ASSERT_THAT(vec, ElementsAre("s1", "s2", "s3"));
 }
 
-
 class ParseFileTests : public Test {
   public:
     RapidJson parser{"filename", true};
@@ -193,27 +189,24 @@ TEST_F(ParseFileTests, CorrectConvertFileToJson) {
     std::string json = R"({"_id":2})";
 
     EXPECT_CALL(mock_io, ReadFileToString_t("filename", _)).
-    WillOnce(DoAll(testing::SetArgPointee<1>(static_cast<hidra2::SimpleError*>(nullptr)), testing::Return(json)));
+    WillOnce(DoAll(testing::SetArgPointee<1>(nullptr), testing::Return(json)));
 
     uint64_t id;
     auto err = parser.GetUInt64("_id", &id);
     ASSERT_THAT(id, Eq(2));
 }
-
-
 TEST_F(ParseFileTests, CannotReadFile) {
     std::string json = R"({"_id":2})";
 
     EXPECT_CALL(mock_io, ReadFileToString_t("filename", _)).
-    WillOnce(DoAll(testing::SetArgPointee<1>(new hidra2::SimpleError(hidra2::IOErrors::kFileNotFound)),
+    WillOnce(DoAll(testing::SetArgPointee<1>(hidra2::IOErrorTemplates::kFileNotFound.Generate().release()),
                    testing::Return("")));
 
     uint64_t id;
     auto err = parser.GetUInt64("_id", &id);
-    ASSERT_THAT(err->Explain(), HasSubstr(hidra2::IOErrors::kFileNotFound));
+    ASSERT_THAT(err->Explain(), HasSubstr(hidra2::IOErrorTemplates::kFileNotFound.Generate()->Explain()));
 
 
 }
 
-
-}
\ No newline at end of file
+}
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index b80aa24186ce17fa1d7ab8e967ad48791c4e5472..ae70ed32ef8c56c1562e5103f200dfc441234863 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -1,3 +1,4 @@
 add_subdirectory(worker)
+add_subdirectory(producer)
 
 
diff --git a/examples/producer/CMakeLists.txt b/examples/producer/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..cac4b634fb8194953cd74efe056680b1dd0722ff
--- /dev/null
+++ b/examples/producer/CMakeLists.txt
@@ -0,0 +1,2 @@
+
+add_subdirectory(dummy-data-producer)
diff --git a/examples/producer/dummy-data-producer/CMakeLists.txt b/examples/producer/dummy-data-producer/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..27851c5910a02919caf96222df6df338548eab74
--- /dev/null
+++ b/examples/producer/dummy-data-producer/CMakeLists.txt
@@ -0,0 +1,34 @@
+set(TARGET_NAME dummy-data-producer)
+set(SOURCE_FILES
+        dummy_data_producer.cpp
+        )
+
+add_executable(${TARGET_NAME} ${SOURCE_FILES})
+target_include_directories(${TARGET_NAME} PUBLIC include ${CMAKE_SOURCE_DIR}/common/cpp/include)
+
+#Add all necessary common libraries
+GET_PROPERTY(HIDRA2_COMMON_IO_LIBRARIES GLOBAL PROPERTY HIDRA2_COMMON_IO_LIBRARIES)
+target_link_libraries(${TARGET_NAME} ${HIDRA2_COMMON_IO_LIBRARIES})
+
+target_link_libraries(${TARGET_NAME} producer-api)
+set_target_properties(${TARGET_NAME} PROPERTIES LINKER_LANGUAGE CXX)
+
+if (CMAKE_COMPILER_IS_GNUCXX)
+    set_target_properties(${TARGET_NAME} PROPERTIES LINK_FLAGS_DEBUG "--coverage")
+endif()
+
+set (dir examples/${TARGET_NAME})
+install(TARGETS ${TARGET_NAME} DESTINATION "${dir}")
+install(FILES ${SOURCE_FILES} DESTINATION "${dir}")
+
+configure_file(CMakeLists_separate.in CMakeLists_separate.txt @ONLY)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/CMakeLists_separate.txt DESTINATION "${dir}" RENAME CMakeLists.txt)
+
+configure_file(Makefile.in Makefile_LINUX @ONLY)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Makefile_LINUX DESTINATION "${dir}")
+
+IF(WIN32)
+add_script_test("${TARGET_NAME}" "${CMAKE_CURRENT_BINARY_DIR}/Debug/${TARGET_NAME}")
+ELSE()
+add_script_test("${TARGET_NAME}" "${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}")
+ENDIF()
diff --git a/examples/producer/dummy-data-producer/CMakeLists_separate.in b/examples/producer/dummy-data-producer/CMakeLists_separate.in
new file mode 100644
index 0000000000000000000000000000000000000000..f0b390f039dd5aefe673005ce6ef99138a70e84f
--- /dev/null
+++ b/examples/producer/dummy-data-producer/CMakeLists_separate.in
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 2.8)
+
+project(@TARGET_NAME@)
+
+set(CMAKE_CXX_STANDARD 11)
+
+IF(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+    SET( CMAKE_EXE_LINKER_FLAGS  "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++")
+ENDIF()
+
+find_package (Threads)
+
+set(TARGET_NAME ${CMAKE_PROJECT_NAME})
+
+set(SOURCE_FILES @SOURCE_FILES@)
+
+link_directories(@CMAKE_INSTALL_PREFIX@/lib)
+
+add_executable(${TARGET_NAME} ${SOURCE_FILES})
+target_include_directories(${TARGET_NAME} PUBLIC @CMAKE_INSTALL_PREFIX@/include)
+target_link_libraries(${TARGET_NAME} producer-api ${CMAKE_THREAD_LIBS_INIT})
diff --git a/examples/producer/dummy-data-producer/Makefile.in b/examples/producer/dummy-data-producer/Makefile.in
new file mode 100644
index 0000000000000000000000000000000000000000..824fb1e946bb2beadd4b4082beeb86640cd2c83c
--- /dev/null
+++ b/examples/producer/dummy-data-producer/Makefile.in
@@ -0,0 +1,25 @@
+PROGRAM=@TARGET_NAME@
+
+CXX=g++
+CXXFLAGS=-std=c++11
+LDFLAGS=-pthread -static-libgcc -static-libstdc++
+LIBS=-L @CMAKE_INSTALL_PREFIX@/lib -lproducer-api
+INCLUDE=-I @CMAKE_INSTALL_PREFIX@/include
+RM=rm -f
+
+SRCS=@SOURCE_FILES@
+OBJS=$(subst .cpp,.o,$(SRCS))
+
+all: $(PROGRAM)
+
+$(PROGRAM): $(OBJS)
+	$(CXX) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+%.o: %.cpp
+	$(CXX) $(CXXFLAGS) $(INCLUDE) -c -o $@ $<
+
+clean:
+	$(RM) $(OBJS)
+
+distclean: clean
+	$(RM) $(PROGRAM)
diff --git a/examples/producer/dummy-data-producer/check_linux.sh b/examples/producer/dummy-data-producer/check_linux.sh
new file mode 100644
index 0000000000000000000000000000000000000000..04f592decbf9d22d1301157df898e0f9c2b764fa
--- /dev/null
+++ b/examples/producer/dummy-data-producer/check_linux.sh
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+
+database_name=test_run
+
+#set -e
+
+
+#just test that it starts, no reciever is running
+$@ 0.0.0.0 1 1 2>&1 | grep "refused"
+
diff --git a/examples/producer/dummy-data-producer/check_windows.bat b/examples/producer/dummy-data-producer/check_windows.bat
new file mode 100644
index 0000000000000000000000000000000000000000..95652e449db3fa550ce10cac2b8040f74a4b54e0
--- /dev/null
+++ b/examples/producer/dummy-data-producer/check_windows.bat
@@ -0,0 +1,9 @@
+"%1" 0.0.0.0 1 1 2>&1 | findstr "not valid" || goto :error
+goto :clean
+
+:error
+call :clean
+exit /b 1
+
+:clean
+
diff --git a/examples/producer/dummy-data-producer/dummy_data_producer.cpp b/examples/producer/dummy-data-producer/dummy_data_producer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a9476d52422276874a68b692957d4d034c19191b
--- /dev/null
+++ b/examples/producer/dummy-data-producer/dummy_data_producer.cpp
@@ -0,0 +1,71 @@
+#include <iostream>
+#include <chrono>
+#include <vector>
+#include <tuple>
+
+#include "hidra2_producer.h"
+
+using std::chrono::high_resolution_clock;
+
+typedef std::tuple<std::string, size_t, uint64_t> ArgumentTuple;
+ArgumentTuple ProcessCommandArguments(int argc, char* argv[]) {
+    if (argc != 4) {
+        std::cout <<
+                  "Usage: " << argv[0] << " <receiver_address> <number_of_byte> <iterations>"
+                  << std::endl;
+        exit(EXIT_FAILURE);
+    }
+    try {
+        return ArgumentTuple(argv[1], std::stoull(argv[2]), std::stoull(argv[3]));
+    } catch(std::exception& e) {
+        std::cerr << "Fail to parse arguments" << std::endl;
+        std::cerr << e.what() << std::endl;
+        exit(EXIT_FAILURE);
+    }
+}
+
+bool SendDummyData(hidra2::Producer* producer, size_t number_of_byte, uint64_t iterations) {
+    auto buffer = std::unique_ptr<uint8_t>(new uint8_t[number_of_byte]);
+
+    for(uint64_t i = 0; i < iterations; i++) {
+        std::cout << "Send file " << i + 1 << "/" << iterations << std::endl;
+
+        auto err = producer->Send(i, buffer.get(), number_of_byte);
+
+        if (err) {
+            std::cerr << "File was not successfully send: " << err << std::endl;
+            return false;
+        } else {
+            std::cout << "File was successfully send." << std::endl;
+        }
+    }
+
+    return true;
+}
+
+int main (int argc, char* argv[]) {
+    std::string receiver_address;
+    size_t number_of_byte;
+    uint64_t iterations;
+    std::tie(receiver_address, number_of_byte, iterations) = ProcessCommandArguments(argc, argv);
+
+    std::cout << "receiver_address: " << receiver_address << std::endl
+              << "number_of_byte: " << number_of_byte << std::endl
+              << "iterations: " << iterations << std::endl
+              << std::endl;
+
+    auto producer = hidra2::Producer::Create();
+    auto err = producer->ConnectToReceiver(receiver_address);
+    if(err) {
+        std::cerr << "Failed to connect to receiver. ProducerError: " << err << std::endl;
+        return EXIT_FAILURE;
+    }
+    std::cout << "Successfully connected" << std::endl;
+
+    if(!SendDummyData(producer.get(), number_of_byte, iterations)) {
+        return EXIT_FAILURE;
+    }
+
+    return EXIT_SUCCESS;
+}
+
diff --git a/examples/worker/CMakeLists.txt b/examples/worker/CMakeLists.txt
index 631b7d02a64b3ef4a11578a767b4d33b2df0d8aa..70c8090c095cbc0c297538a0f4e3b0e74ddef854 100644
--- a/examples/worker/CMakeLists.txt
+++ b/examples/worker/CMakeLists.txt
@@ -3,4 +3,3 @@ find_package(Threads)
 add_subdirectory(process_folder)
 
 add_subdirectory(getnext_broker)
-
diff --git a/examples/worker/getnext_broker/check_linux.sh b/examples/worker/getnext_broker/check_linux.sh
index d4b766bc430880ca310e37608a0822100b1ad005..b00865d7b4e2533221ce2c40f447ce559dce9abc 100644
--- a/examples/worker/getnext_broker/check_linux.sh
+++ b/examples/worker/getnext_broker/check_linux.sh
@@ -24,6 +24,5 @@ do
 	echo 'db.data.insert({"_id":'$i',"size":100,"name":"'$i'","lastchange":1})' | mongo ${database_name}
 done
 
-$args 127.0.0.1:5005 $database_name 2
-#| grep "Processed 3 file(s)"
+$args 127.0.0.1:5005 $database_name 2 | grep "Processed 3 file(s)"
 
diff --git a/examples/worker/getnext_broker/getnext_broker.cpp b/examples/worker/getnext_broker/getnext_broker.cpp
index 0f578333b51ffb444c7ca0204a9d11e87883c66c..3c5a43d0677555276b0f25aaf2aed1768272c7fe 100644
--- a/examples/worker/getnext_broker/getnext_broker.cpp
+++ b/examples/worker/getnext_broker/getnext_broker.cpp
@@ -20,7 +20,7 @@ void WaitThreads(std::vector<std::thread>* threads) {
 
 void ProcessError(const Error& err) {
     if (err == nullptr) return;
-    if (err->GetErrorType() != hidra2::ErrorType::kEOF) {
+    if (err->GetErrorType() != hidra2::ErrorType::kEndOfFile) {
         std::cout << err->Explain() << std::endl;
         exit(EXIT_FAILURE);
     }
diff --git a/examples/worker/process_folder/CMakeLists.txt b/examples/worker/process_folder/CMakeLists.txt
index 0c0d05d73cb46d7295e078d39f74090acd9a3a95..ea20503288ce7e01cc57dd3ff121905981d6703d 100644
--- a/examples/worker/process_folder/CMakeLists.txt
+++ b/examples/worker/process_folder/CMakeLists.txt
@@ -2,7 +2,12 @@ set(TARGET_NAME worker_processfolder)
 set(SOURCE_FILES process_folder.cpp)
 
 add_executable(${TARGET_NAME} ${SOURCE_FILES})
-target_link_libraries(${TARGET_NAME} hidra2-worker ${CMAKE_THREAD_LIBS_INIT})
+
+#Add all necessary common libraries
+GET_PROPERTY(HIDRA2_COMMON_IO_LIBRARIES GLOBAL PROPERTY HIDRA2_COMMON_IO_LIBRARIES)
+target_link_libraries(${TARGET_NAME} ${HIDRA2_COMMON_IO_LIBRARIES})
+
+target_link_libraries(${TARGET_NAME} hidra2-worker)
 set_target_properties(${TARGET_NAME} PROPERTIES LINKER_LANGUAGE CXX)
 #use expression generator to get rid of VS adding Debug/Release folders
 set_target_properties(${TARGET_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY
diff --git a/examples/worker/process_folder/check_linux.sh b/examples/worker/process_folder/check_linux.sh
old mode 100644
new mode 100755
diff --git a/examples/worker/process_folder/process_folder.cpp b/examples/worker/process_folder/process_folder.cpp
index fd789d2fdf1df19cde1564c4b7fe85f03669e286..f85f7257385f15b092f5598ee7e4e84daa5b95d6 100644
--- a/examples/worker/process_folder/process_folder.cpp
+++ b/examples/worker/process_folder/process_folder.cpp
@@ -60,7 +60,7 @@ void ReadAllData(std::unique_ptr<hidra2::DataBroker>* broker, Statistics* statis
         nfiles++;
         size += file_info.size;
     }
-    if (err->GetErrorType() != hidra2::ErrorType::kEOF) {
+    if (err->GetErrorType() != hidra2::ErrorType::kEndOfFile) {
         std::cout << err->Explain() << std::endl;
         exit(EXIT_FAILURE);
     }
diff --git a/producer/CMakeLists.txt b/producer/CMakeLists.txt
index 0d50d291afaac3aedb56552609d99d712a59c8a1..53d257b04ea6ffc4b663736b9d8bd559dc341222 100644
--- a/producer/CMakeLists.txt
+++ b/producer/CMakeLists.txt
@@ -1 +1 @@
-add_subdirectory(inotify-event-detector-cpp)
+add_subdirectory(api)
diff --git a/producer/api/CMakeLists.txt b/producer/api/CMakeLists.txt
index db938ae4c1ad7dde2364954b8600eee6d27cc698..2c9da5a959a00b8ef2069aaf71d1c9479ce18c7f 100644
--- a/producer/api/CMakeLists.txt
+++ b/producer/api/CMakeLists.txt
@@ -1,5 +1,9 @@
 set(TARGET_NAME producer-api)
-set(SOURCE_FILES src/producer/producer.cpp include/producer/producer.h)
+set(SOURCE_FILES
+        src/producer.cpp
+        src/producer_impl.h
+        src/producer_impl.cpp
+        )
 
 
 ################################
@@ -8,14 +12,20 @@ set(SOURCE_FILES src/producer/producer.cpp include/producer/producer.h)
 add_library(${TARGET_NAME} STATIC ${SOURCE_FILES} $<TARGET_OBJECTS:system_io>)
 target_include_directories(${TARGET_NAME} PUBLIC include)
 set_target_properties(${TARGET_NAME} PROPERTIES LINKER_LANGUAGE CXX)
+target_include_directories(${TARGET_NAME} PUBLIC ${HIDRA2_CXX_COMMON_INCLUDE_DIR})
 
 ################################
 # Testing
 ################################
-set(TEST_SOURCE_FILES unittests/test_producer.cpp)
-set(TEST_LIBRARIES producer-api)
+set(TEST_SOURCE_FILES
+        unittests/test_producer_impl.cpp
+        unittests/test_producer.cpp
+        )
+set(TEST_LIBRARIES "${TARGET_NAME}")
 
 
-gtest(${TARGET_NAME} ${TEST_SOURCE_FILES} ${TEST_LIBRARIES})
+gtest(${TARGET_NAME} "${TEST_SOURCE_FILES}" "${TEST_LIBRARIES}")
 
+install(TARGETS ${TARGET_NAME} DESTINATION lib)
 
+install(DIRECTORY include/ DESTINATION include)
diff --git a/producer/api/include/hidra2_producer.h b/producer/api/include/hidra2_producer.h
new file mode 100644
index 0000000000000000000000000000000000000000..7cb5d2431367beccc455cecbc333c804414ac66c
--- /dev/null
+++ b/producer/api/include/hidra2_producer.h
@@ -0,0 +1,8 @@
+#ifndef HIDRA2_HIDRA2_PRODUCER_H
+#define HIDRA2_HIDRA2_PRODUCER_H
+
+#include "common/io_error.h"
+#include "producer/producer.h"
+
+
+#endif //HIDRA2_HIDRA2_PRODUCER_H
diff --git a/producer/api/include/producer/producer.h b/producer/api/include/producer/producer.h
index 674836c52d330d3c662efe3204ca33027a1d25de..3f7583875ece1fe62017cd9445865a0b25e905eb 100644
--- a/producer/api/include/producer/producer.h
+++ b/producer/api/include/producer/producer.h
@@ -1,21 +1,53 @@
-#ifndef HIDRA2__PRODUCER_PRODUCER_H
-#define HIDRA2__PRODUCER_PRODUCER_H
+#ifndef HIDRA2_PRODUCER__PRODUCER_H
+#define HIDRA2_PRODUCER__PRODUCER_H
 
+#include <memory>
 #include <string>
 
+#include "producer_error.h"
+
 namespace hidra2 {
+
+enum class ProducerStatus {
+    kDisconnected,
+    kConnected,
+};
+
 class Producer {
-  private:
-    static unsigned long kinit_count_;
-    Producer();
   public:
-    static const uint32_t VERSION;
+    //! Creates a new producer
+    /*!
+     * @return A unique_ptr to a new producer instance
+     */
+    static std::unique_ptr<Producer> Create();
+
+    virtual ~Producer() = default;
+
+    /*!
+     * @return The version of the producer
+     */
+    virtual uint64_t GetVersion() const = 0;
 
-    Producer(const Producer&) = delete;
-    Producer& operator=(const Producer&) = delete;
+    /*!
+     * @return The current status of the producer
+     */
+    virtual ProducerStatus GetStatus() const = 0;
 
-    static Producer* CreateProducer(std::string receiver_address);
+    //! Connects to a receiver
+    /*!
+      \param receiver_address - The address of the receiver. E.g. 127.0.0.1:4200
+      \return Error - nullptr on success
+    */
+    virtual Error ConnectToReceiver(const std::string& receiver_address) = 0;
+    //! Sends data to the receiver
+    /*!
+      \param file_id - The id of the file. An error will be returned if this file id already exists on the receiver.
+      \param data - A pointer to the data to send
+      \param file_size - The size of the data.
+      \return Error - Will be nullptr on success
+    */
+    virtual Error Send(uint64_t file_id, const void* data, size_t file_size) = 0;
 };
 }
 
-#endif //HIDRA2__PRODUCER_PRODUCER_H
+#endif //HIDRA2_PRODUCER__PRODUCER_H
diff --git a/producer/api/include/producer/producer_error.h b/producer/api/include/producer/producer_error.h
new file mode 100644
index 0000000000000000000000000000000000000000..cdcf69a742ad54dd6d248f654e56953ce6faf701
--- /dev/null
+++ b/producer/api/include/producer/producer_error.h
@@ -0,0 +1,78 @@
+#ifndef HIDRA2_PRODUCER_ERROR_H
+#define HIDRA2_PRODUCER_ERROR_H
+
+#include "common/error.h"
+
+namespace hidra2 {
+
+enum class ProducerErrorType {
+    kAlreadyConnected,
+    kConnectionNotReady,
+    kFileTooLarge,
+    kFileIdAlreadyInUse,
+    kUnknownServerError
+};
+
+//TODO Make a marco to create error class and error template class
+class ProducerError : public SimpleError {
+  private:
+    ProducerErrorType receiver_error_type_;
+  public:
+    ProducerError(const std::string& error, ProducerErrorType receiver_error_type) : SimpleError(error,
+                ErrorType::kProducerError) {
+        receiver_error_type_ = receiver_error_type;
+    }
+
+    ProducerErrorType GetProducerErrorType() const noexcept {
+        return receiver_error_type_;
+    }
+};
+
+class ProducerErrorTemplate : public SimpleErrorTemplate {
+  protected:
+    ProducerErrorType receiver_error_type_;
+  public:
+    ProducerErrorTemplate(const std::string& error, ProducerErrorType receiver_error_type) : SimpleErrorTemplate(error,
+                ErrorType::kProducerError) {
+        receiver_error_type_ = receiver_error_type;
+    }
+
+    inline ProducerErrorType GetProducerErrorType() const noexcept {
+        return receiver_error_type_;
+    }
+
+    inline Error Generate() const noexcept override {
+        return Error(new ProducerError(error_, receiver_error_type_));
+    }
+
+    inline bool operator==(const Error& rhs) const override {
+        return SimpleErrorTemplate::operator==(rhs)
+               && GetProducerErrorType() == ((ProducerError*) rhs.get())->GetProducerErrorType();
+    }
+};
+
+namespace ProducerErrorTemplates {
+auto const kAlreadyConnected = ProducerErrorTemplate {
+    "Already connected", ProducerErrorType::kAlreadyConnected
+};
+auto const kConnectionNotReady = ProducerErrorTemplate {
+    "Connection not ready", ProducerErrorType::kConnectionNotReady
+};
+
+auto const kFileTooLarge = ProducerErrorTemplate {
+    "File too large", ProducerErrorType::kFileTooLarge
+};
+
+auto const kFileIdAlreadyInUse = ProducerErrorTemplate {
+    "File already in use", ProducerErrorType::kFileIdAlreadyInUse
+};
+
+auto const kUnknownServerError = ProducerErrorTemplate {
+    "Unknown server error", ProducerErrorType::kUnknownServerError
+};
+
+
+};
+}
+
+#endif //HIDRA2_PRODUCER_ERROR_H
diff --git a/producer/api/src/producer.cpp b/producer/api/src/producer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..25add6276cc3bf432fc4a8a07069e112890b384a
--- /dev/null
+++ b/producer/api/src/producer.cpp
@@ -0,0 +1,6 @@
+#include "producer/producer.h"
+#include "producer_impl.h"
+
+std::unique_ptr<hidra2::Producer> hidra2::Producer::Create() {
+    return std::unique_ptr<hidra2::Producer>(new ProducerImpl());
+}
diff --git a/producer/api/src/producer/producer.cpp b/producer/api/src/producer/producer.cpp
deleted file mode 100644
index f4373a91db6b1098bc85595a3567f7b3de5577df..0000000000000000000000000000000000000000
--- a/producer/api/src/producer/producer.cpp
+++ /dev/null
@@ -1,12 +0,0 @@
-#include <producer/producer.h>
-
-unsigned long hidra2::Producer::kinit_count_ = 0;
-const uint32_t hidra2::Producer::VERSION = 1;
-
-hidra2::Producer::Producer() {
-    kinit_count_++;
-}
-
-hidra2::Producer* hidra2::Producer::CreateProducer(std::string receiver_address) {
-    return new Producer();
-}
diff --git a/producer/api/src/producer_impl.cpp b/producer/api/src/producer_impl.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f3ec4e49a7b2b145fd6b62d40c95743010afd163
--- /dev/null
+++ b/producer/api/src/producer_impl.cpp
@@ -0,0 +1,113 @@
+#include <iostream>
+#include <cstring>
+
+#include "producer_impl.h"
+#include "io/io_factory.h"
+
+namespace  hidra2 {
+
+const uint32_t ProducerImpl::kVersion = 1;
+const size_t ProducerImpl::kMaxChunkSize = size_t(1024) * size_t(1024) * size_t(1024) * size_t(2); //2GiByte
+
+ProducerImpl::ProducerImpl(): io__{GenerateDefaultIO()} {
+}
+
+uint64_t ProducerImpl::GetVersion() const {
+    return kVersion;
+}
+
+ProducerStatus ProducerImpl::GetStatus() const {
+    return status_;
+}
+
+Error ProducerImpl::InitializeSocketToReceiver(const std::string& receiver_address) {
+    Error err;
+    FileDescriptor fd = io__->CreateAndConnectIPTCPSocket(receiver_address, &err);
+    if(err != nullptr) {
+        return err;
+    }
+
+    client_fd_ = fd;
+    return nullptr;
+}
+
+Error ProducerImpl::ConnectToReceiver(const std::string& receiver_address) {
+    if(status_ != ProducerStatus::kDisconnected) {
+        return ProducerErrorTemplates::kAlreadyConnected.Generate();
+    }
+
+    auto error = InitializeSocketToReceiver(receiver_address);
+    if(error) {
+        status_ = ProducerStatus::kDisconnected;
+        return error;
+    }
+
+    status_ = ProducerStatus::kConnected;
+    return nullptr;
+}
+
+GenericNetworkRequestHeader ProducerImpl::GenerateNextSendRequest(uint64_t file_id, size_t file_size) {
+    GenericNetworkRequestHeader request;
+    request.op_code = kNetOpcodeSendData;
+    request.request_id = request_id_++;
+    request.data_id = file_id;
+    request.data_size = file_size;
+    return request;
+}
+
+Error ProducerImpl::SendHeaderAndData(const GenericNetworkRequestHeader& header, const void* data, size_t file_size) {
+    Error io_error;
+    io__->Send(client_fd_, &header, sizeof(header), &io_error);
+    if(io_error) {
+        std::cerr << "ProducerImpl::Send/DataRequest error" << io_error << std::endl;
+        return io_error;
+    }
+
+    io__->Send(client_fd_, data, file_size, &io_error);
+    if(io_error) {
+        std::cerr << "ProducerImpl::Send/data error" << io_error << std::endl;
+        return io_error;
+    }
+
+    return nullptr;
+}
+
+Error ProducerImpl::ReceiveResponce() {
+    Error err;
+    SendDataResponse sendDataResponse;
+    io__->Receive(client_fd_, &sendDataResponse, sizeof(sendDataResponse), &err);
+    if(err != nullptr) {
+        std::cerr << "ProducerImpl::Receive error: " << err << std::endl;
+        return err;
+    }
+
+    if(sendDataResponse.error_code) {
+        if(sendDataResponse.error_code == kNetErrorFileIdAlreadyInUse) {
+            return ProducerErrorTemplates::kFileIdAlreadyInUse.Generate();
+        }
+        std::cerr << "Server reported an error. NetErrorCode: " << int(sendDataResponse.error_code) << std::endl;
+        return ProducerErrorTemplates::kUnknownServerError.Generate();
+    }
+    return nullptr;
+}
+
+
+Error ProducerImpl::Send(uint64_t file_id, const void* data, size_t file_size) {
+    if(status_ != ProducerStatus::kConnected) {
+        return ProducerErrorTemplates::kConnectionNotReady.Generate();
+    }
+    if(file_size > kMaxChunkSize) {
+        return ProducerErrorTemplates::kFileTooLarge.Generate();
+    }
+
+    auto send_data_request = GenerateNextSendRequest(file_id, file_size);
+
+    auto  error = SendHeaderAndData(send_data_request, data, file_size);
+    if(error) {
+        return error;
+    }
+
+    return ReceiveResponce();
+}
+
+}
\ No newline at end of file
diff --git a/producer/api/src/producer_impl.h b/producer/api/src/producer_impl.h
new file mode 100644
index 0000000000000000000000000000000000000000..05797c5058dc06d7fca68bf001f71b0be2365d34
--- /dev/null
+++ b/producer/api/src/producer_impl.h
@@ -0,0 +1,39 @@
+#ifndef HIDRA2_PRODUCER__PRODUCER_IMPL_H
+#define HIDRA2_PRODUCER__PRODUCER_IMPL_H
+
+#include <string>
+#include <common/networking.h>
+#include <io/io.h>
+#include "producer/producer.h"
+
+namespace hidra2 {
+class ProducerImpl : public Producer {
+  private:
+    static const uint32_t kVersion;
+
+    int         client_fd_ = -1;
+    uint64_t    request_id_ = 0;
+
+    ProducerStatus status_ = ProducerStatus::kDisconnected;
+
+    Error InitializeSocketToReceiver(const std::string& receiver_address);
+    GenericNetworkRequestHeader GenerateNextSendRequest(uint64_t file_id, size_t file_size);
+    Error SendHeaderAndData(const GenericNetworkRequestHeader& header, const void* data, size_t file_size);
+    Error ReceiveResponce();
+
+  public:
+    static const size_t kMaxChunkSize;
+
+    ProducerImpl();
+    ProducerImpl(const ProducerImpl&) = delete;
+    ProducerImpl& operator=(const ProducerImpl&) = delete;
+
+    uint64_t GetVersion() const override;
+    ProducerStatus GetStatus() const override;
+    Error ConnectToReceiver(const std::string& receiver_address) override;
+    Error Send(uint64_t file_id, const void* data, size_t file_size) override;
+    std::unique_ptr<IO> io__;
+};
+}
+
+#endif //HIDRA2_PRODUCER__PRODUCER_IMPL_H
diff --git a/producer/api/unittests/test_producer.cpp b/producer/api/unittests/test_producer.cpp
index 6522702215d4ce9f78a110dba4983c71c9e1dc69..91b1f691a6a541cef3da6f69a694c87353574b20 100644
--- a/producer/api/unittests/test_producer.cpp
+++ b/producer/api/unittests/test_producer.cpp
@@ -1,14 +1,16 @@
 #include <gtest/gtest.h>
-#include <producer/producer.h>
+#include <unittests/MockIO.h>
+
+#include "producer/producer.h"
+#include "../src/producer_impl.h"
+using ::testing::Ne;
 
 namespace {
-TEST(VERSION, VersionAboveZero) {
-    EXPECT_GE(hidra2::Producer::VERSION, 0);
-}
 
 TEST(CreateProducer, PointerIsNotNullptr) {
-    hidra2::Producer* prod = hidra2::Producer::CreateProducer("127.0.0.1");
-    EXPECT_NE(prod, nullptr);
-    delete prod;
+    std::unique_ptr<hidra2::Producer> producer = hidra2::Producer::Create();
+    ASSERT_THAT(dynamic_cast<hidra2::ProducerImpl*>(producer.get()), Ne(nullptr));
+    ASSERT_THAT(producer.get(), Ne(nullptr));
 }
+
 }
diff --git a/producer/api/unittests/test_producer_impl.cpp b/producer/api/unittests/test_producer_impl.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3733166493d6c6397c7229f2f3767bf4cac6421c
--- /dev/null
+++ b/producer/api/unittests/test_producer_impl.cpp
@@ -0,0 +1,275 @@
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+#include <unittests/MockIO.h>
+
+#include "common/error.h"
+#include "io/io.h"
+#include "producer/producer.h"
+#include "../src/producer_impl.h"
+
+namespace {
+using ::testing::Return;
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::SetArgReferee;
+using ::testing::Gt;
+using ::testing::Eq;
+using ::testing::Mock;
+using ::testing::InSequence;
+
+TEST(get_version, VersionAboveZero) {
+    hidra2::ProducerImpl producer;
+    EXPECT_GE(producer.GetVersion(), 0);
+}
+
+
+/**
+ * ConnectToReceiver
+ */
+
+class ProducerImpl : public testing::Test {
+  public:
+    hidra2::ProducerImpl producer;
+    testing::NiceMock<hidra2::MockIO> mock_io;
+    hidra2::FileDescriptor expected_fd = 83942;
+    uint64_t expected_file_id = 4224;
+    std::string expected_address = "127.0.0.1:9090";
+    uint64_t expected_request_id = 0;
+    uint64_t expected_file_size = 1337;
+    void*    expected_file_pointer = (void*)0xC00FE;
+
+    void SetUp() override {
+        producer.io__ = std::unique_ptr<hidra2::IO> {&mock_io};
+    }
+    void TearDown() override {
+        producer.io__.release();
+    }
+
+    void ConnectToReceiver_DONE(hidra2::FileDescriptor expected_fd = 1) {
+        EXPECT_CALL(mock_io, CreateAndConnectIPTCPSocket_t(_, _))
+        .Times(1)
+        .WillOnce(
+            DoAll(
+                testing::SetArgPointee<1>(nullptr),
+                Return(expected_fd)
+            ));
+        producer.ConnectToReceiver("");
+    }
+    void Send_DONE(int times = 1) {
+        EXPECT_CALL(mock_io, Send_t(_, _, _, _))
+        .Times(times)
+        .WillRepeatedly(
+            DoAll(
+                testing::SetArgPointee<3>(nullptr),
+                testing::ReturnArg<2>()
+            ));
+    }
+};
+
+TEST_F(ProducerImpl, get_status__disconnected) {
+    hidra2::ProducerStatus status = producer.GetStatus();
+    ASSERT_THAT(status, Eq(hidra2::ProducerStatus::kDisconnected));
+}
+
+
+TEST_F(ProducerImpl, ConnectToReceiver__CreateAndConnectIPTCPSocket_error) {
+    EXPECT_CALL(mock_io, CreateAndConnectIPTCPSocket_t(expected_address, _))
+    .Times(1)
+    .WillOnce(
+        DoAll(
+            testing::SetArgPointee<1>(hidra2::IOErrorTemplates::kInvalidAddressFormat.Generate().release()),
+            Return(-1)
+        ));
+
+    auto error = producer.ConnectToReceiver(expected_address);
+    auto status = producer.GetStatus();
+
+    ASSERT_THAT(error, Eq(hidra2::IOErrorTemplates::kInvalidAddressFormat));
+    ASSERT_THAT(status, Eq(hidra2::ProducerStatus::kDisconnected));
+}
+
+TEST_F(ProducerImpl, ConnectToReceiver) {
+    EXPECT_CALL(mock_io, CreateAndConnectIPTCPSocket_t(expected_address, _))
+    .Times(1)
+    .WillOnce(
+        DoAll(
+            testing::SetArgPointee<1>(nullptr),
+            Return(expected_fd)
+        ));
+
+    auto error = producer.ConnectToReceiver(expected_address);
+    auto status = producer.GetStatus();
+
+    ASSERT_THAT(error, Eq(nullptr));
+    ASSERT_THAT(status, Eq(hidra2::ProducerStatus::kConnected));
+}
+
+TEST_F(ProducerImpl, ConnectToReceiver__already_connected) {
+    InSequence sequence;
+
+    ConnectToReceiver_DONE();
+
+    auto error = producer.ConnectToReceiver(expected_address);
+
+    ASSERT_THAT(error, Eq(hidra2::ProducerErrorTemplates::kAlreadyConnected));
+}
+
+/**
+ * Send
+ */
+
+MATCHER_P3(M_CheckSendDataRequest, request_id, file_id, file_size,
+           "Checks if a valid GenericNetworkRequestHeader was Send") {
+    return ((hidra2::GenericNetworkRequestHeader*)arg)->op_code == hidra2::kNetOpcodeSendData
+           && ((hidra2::GenericNetworkRequestHeader*)arg)->request_id == request_id
+           && ((hidra2::GenericNetworkRequestHeader*)arg)->data_id == file_id
+           && ((hidra2::GenericNetworkRequestHeader*)arg)->data_size == file_size;
+}
+
+ACTION_P2(A_WriteSendDataResponse, error_code, request_id) {
+    ((hidra2::SendDataResponse*)arg1)->op_code = hidra2::kNetOpcodeSendData;
+    ((hidra2::SendDataResponse*)arg1)->error_code = error_code;
+    ((hidra2::SendDataResponse*)arg1)->request_id = request_id;
+}
+
+TEST_F(ProducerImpl, Send__connection_not_ready) {
+
+    auto error = producer.Send(expected_file_id, nullptr, 1);
+
+    ASSERT_THAT(error, Eq(hidra2::ProducerErrorTemplates::kConnectionNotReady));
+}
+
+TEST_F(ProducerImpl, Send__file_too_large) {
+
+    ConnectToReceiver_DONE(expected_fd);
+
+    auto error = producer.Send(expected_file_id, nullptr,
+                               size_t(1024) * size_t(1024) * size_t(1024) * size_t(3));
+
+    ASSERT_THAT(error, Eq(hidra2::ProducerErrorTemplates::kFileTooLarge));
+}
+
+TEST_F(ProducerImpl, Send__sendDataRequest_error) {
+    InSequence sequence;
+
+    ConnectToReceiver_DONE(expected_fd);
+
+    EXPECT_CALL(mock_io, Send_t(expected_fd, M_CheckSendDataRequest(expected_request_id, expected_file_id,
+                                expected_file_size),
+                                sizeof(hidra2::GenericNetworkRequestHeader), _))
+    .Times(1)
+    .WillOnce(
+        DoAll(
+            testing::SetArgPointee<3>(hidra2::IOErrorTemplates::kBadFileNumber.Generate().release()),
+            Return(-1)
+        ));
+
+    auto error = producer.Send(expected_file_id, nullptr, expected_file_size);
+
+    ASSERT_THAT(error, Eq(hidra2::IOErrorTemplates::kBadFileNumber));
+}
+
+TEST_F(ProducerImpl, Send__sendData_error) {
+    InSequence sequence;
+
+    ConnectToReceiver_DONE(expected_fd);
+    Send_DONE();
+
+    EXPECT_CALL(mock_io, Send_t(expected_fd, expected_file_pointer, expected_file_size, _))
+    .Times(1)
+    .WillOnce(
+        DoAll(
+            testing::SetArgPointee<3>(hidra2::IOErrorTemplates::kBadFileNumber.Generate().release()),
+            Return(-1)
+        ));
+
+
+    auto error = producer.Send(expected_file_id, expected_file_pointer, expected_file_size);
+
+    ASSERT_THAT(error, Eq(hidra2::IOErrorTemplates::kBadFileNumber));
+}
+
+
+TEST_F(ProducerImpl, Send__Receive_error) {
+    InSequence sequence;
+
+    ConnectToReceiver_DONE(expected_fd);
+    Send_DONE(2);
+
+    EXPECT_CALL(mock_io, Receive_t(expected_fd, _, sizeof(hidra2::SendDataResponse), _))
+    .Times(1)
+    .WillOnce(
+        DoAll(
+            testing::SetArgPointee<3>(hidra2::IOErrorTemplates::kBadFileNumber.Generate().release()),
+            testing::Return(-1)
+        ));
+
+    auto error = producer.Send(expected_file_id, expected_file_pointer, expected_file_size);
+
+    ASSERT_THAT(error, Eq(hidra2::IOErrorTemplates::kBadFileNumber));
+}
+
+TEST_F(ProducerImpl, Send__Receive_server_error) {
+    InSequence sequence;
+
+    ConnectToReceiver_DONE(expected_fd);
+    Send_DONE(2);
+
+
+    EXPECT_CALL(mock_io, Receive_t(_, _, sizeof(hidra2::SendDataResponse), _))
+    .Times(1)
+    .WillOnce(
+        DoAll(
+            testing::SetArgPointee<3>(nullptr),
+            A_WriteSendDataResponse(hidra2::kNetErrorAllocateStorageFailed, expected_request_id),
+            testing::ReturnArg<2>()
+        ));
+
+    auto error = producer.Send(expected_file_id, expected_file_pointer, expected_file_size);
+
+    ASSERT_THAT(error, Eq(hidra2::ProducerErrorTemplates::kUnknownServerError));
+}
+
+TEST_F(ProducerImpl, Send__Receive_server_error_id_already_in_use) {
+    InSequence sequence;
+
+    ConnectToReceiver_DONE(expected_fd);
+    Send_DONE(2);
+
+
+    EXPECT_CALL(mock_io, Receive_t(_, _, sizeof(hidra2::SendDataResponse), _))
+    .Times(1)
+    .WillOnce(
+        DoAll(
+            testing::SetArgPointee<3>(nullptr),
+            A_WriteSendDataResponse(hidra2::kNetErrorFileIdAlreadyInUse, expected_request_id),
+            testing::ReturnArg<2>()
+        ));
+
+    auto error = producer.Send(expected_file_id, expected_file_pointer, expected_file_size);
+
+    ASSERT_THAT(error, Eq(hidra2::ProducerErrorTemplates::kFileIdAlreadyInUse));
+}
+
+TEST_F(ProducerImpl, Send) {
+    InSequence sequence;
+
+    ConnectToReceiver_DONE(expected_fd);
+    Send_DONE(2);
+
+
+    EXPECT_CALL(mock_io, Receive_t(_, _, sizeof(hidra2::SendDataResponse), _))
+    .Times(1)
+    .WillOnce(
+        DoAll(
+            testing::SetArgPointee<3>(nullptr),
+            A_WriteSendDataResponse(hidra2::kNetErrorNoError, expected_request_id),
+            testing::ReturnArg<2>()
+        ));
+
+    auto error = producer.Send(expected_file_id, expected_file_pointer, expected_file_size);
+
+    ASSERT_THAT(error, Eq(nullptr));
+}
+
+}
diff --git a/producer/inotify-event-detector-cpp/CMakeLists.txt b/producer/inotify-event-detector-cpp/CMakeLists.txt
deleted file mode 100644
index dcb6da5431f4b6f4bd99004f33daeb122739dcdd..0000000000000000000000000000000000000000
--- a/producer/inotify-event-detector-cpp/CMakeLists.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-set(TARGET_NAME inotify-event-detector-cpp)
-set(SOURCE_FILES src/main.cpp)
-
-
-################################
-# Executable and link
-################################
-add_executable(${TARGET_NAME} ${SOURCE_FILES})
-target_include_directories(${TARGET_NAME} PRIVATE include)
-target_link_libraries(${TARGET_NAME} common producer-api)
-set_target_properties(${TARGET_NAME} PROPERTIES LINKER_LANGUAGE CXX)
-
-################################
-# Testing
-################################
-set(TEST_SOURCE_FILES unittests/test_inotify_client.cpp)
-
-
-#gtest(${TARGET_NAME} ${TEST_SOURCE_FILES} "")
diff --git a/producer/inotify-event-detector-cpp/src/main.cpp b/producer/inotify-event-detector-cpp/src/main.cpp
deleted file mode 100644
index 62d77f036cc0be9f6da7bd1728fbe931c97e95db..0000000000000000000000000000000000000000
--- a/producer/inotify-event-detector-cpp/src/main.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-#include <producer/producer.h>
-#include <iostream>
-
-int main (int argc, char* argv[]) {
-    std::cout << "Running producer version: " << hidra2::Producer::VERSION << std::endl;
-
-    hidra2::Producer* producer = hidra2::Producer::CreateProducer("127.0.0.1");
-    if(!producer) {
-        std::cerr << "Fail to create producer" << std::endl;
-        return 1;
-    }
-
-    std::cout << "Successfully create producer " << std::hex << producer << std::endl;
-
-    return 0;
-}
diff --git a/producer/inotify-event-detector-cpp/unittests/test_inotify_client.cpp b/producer/inotify-event-detector-cpp/unittests/test_inotify_client.cpp
deleted file mode 100644
index 1e1b911ef88017e2c98dc5915b52b210f2e18fbf..0000000000000000000000000000000000000000
--- a/producer/inotify-event-detector-cpp/unittests/test_inotify_client.cpp
+++ /dev/null
@@ -1,5 +0,0 @@
-#include <gtest/gtest.h>
-
-TEST(EMPTY, REMOVEME) {
-    EXPECT_EQ(1, 1);
-}
diff --git a/receiver/CMakeLists.txt b/receiver/CMakeLists.txt
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3fd260ef2dad27c224f83a2311bca432f79626e3 100644
--- a/receiver/CMakeLists.txt
+++ b/receiver/CMakeLists.txt
@@ -0,0 +1,41 @@
+set(TARGET_NAME receiver)
+set(SOURCE_FILES
+        src/receiver.h src/receiver.cpp
+        src/connection.h src/connection.cpp
+        src/receiver_error.h
+        src/request.cpp
+        src/request_handler_file_write.cpp
+        )
+
+
+################################
+# Library
+################################
+add_library(${TARGET_NAME} STATIC ${SOURCE_FILES} $<TARGET_OBJECTS:system_io>)
+set_target_properties(${TARGET_NAME} PROPERTIES LINKER_LANGUAGE CXX)
+target_include_directories(${TARGET_NAME} PUBLIC ${HIDRA2_CXX_COMMON_INCLUDE_DIR})
+
+add_executable(${TARGET_NAME}-bin src/main.cpp)
+set_target_properties(${TARGET_NAME}-bin PROPERTIES OUTPUT_NAME ${TARGET_NAME})
+target_link_libraries(${TARGET_NAME}-bin ${TARGET_NAME})
+
+#Add all necessary common libraries
+GET_PROPERTY(HIDRA2_COMMON_IO_LIBRARIES GLOBAL PROPERTY HIDRA2_COMMON_IO_LIBRARIES)
+target_link_libraries(${TARGET_NAME}-bin ${HIDRA2_COMMON_IO_LIBRARIES})
+set_target_properties(${TARGET_NAME}-bin PROPERTIES LINKER_LANGUAGE CXX)
+
+################################
+# Testing
+################################
+
+set_property(TARGET ${TARGET_NAME} PROPERTY ENABLE_EXPORTS true)
+#
+set(TEST_SOURCE_FILES
+        unittests/test_receiver.cpp
+        unittests/test_connection.cpp
+        unittests/test_request.cpp
+        unittests/test_request_handler_file_write.cpp
+        )
+#
+set(TEST_LIBRARIES "${TARGET_NAME};system_io")
+gtest(${TARGET_NAME} "${TEST_SOURCE_FILES}" "${TEST_LIBRARIES}" ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp)
diff --git a/receiver/src/connection.cpp b/receiver/src/connection.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b97358222717c8f4e26dad76f22d4bd56b9a276e
--- /dev/null
+++ b/receiver/src/connection.cpp
@@ -0,0 +1,82 @@
+#include <cstring>
+#include <assert.h>
+#include "connection.h"
+#include "receiver_error.h"
+#include "io/io_factory.h"
+
+namespace hidra2 {
+
+size_t Connection::kRequestHandlerMaxBufferSize;
+std::atomic<uint32_t> Connection::kNetworkProducerPeerImplGlobalCounter(0);
+
+Connection::Connection(SocketDescriptor socket_fd, const std::string& address): request_factory__{new RequestFactory},
+io__{GenerateDefaultIO()} {
+    socket_fd_ = socket_fd;
+    connection_id_ = kNetworkProducerPeerImplGlobalCounter++;
+    address_ = address;
+}
+
+uint64_t Connection::GetId() const noexcept {
+    return connection_id_;
+}
+
+NetworkErrorCode GetNetworkCodeFromError(const Error& err) {
+    if(err) {
+        if(err == IOErrorTemplates::kFileAlreadyExists) {
+            return NetworkErrorCode::kNetErrorFileIdAlreadyInUse;
+        } else {
+            return NetworkErrorCode::kNetErrorInternalServerError;
+        }
+    }
+    return NetworkErrorCode::kNetErrorNoError;
+
+}
+
+Error Connection::ProcessRequest(const std::unique_ptr<Request>& request) const noexcept {
+    Error err;
+    err = request->Handle();
+    GenericNetworkResponse generic_response;
+    generic_response.error_code = GetNetworkCodeFromError(err);
+    if(err) {
+        std::cerr << "[" << GetId() << "] Error while handling request: " << err << std::endl;
+    }
+    io__->Send(socket_fd_, &generic_response, sizeof(GenericNetworkResponse), &err);
+    return err;
+}
+
+
+void Connection::Listen() const noexcept {
+    while(true) {
+        Error err;
+        auto request = WaitForNewRequest(&err);
+        if(err) {
+            std::cerr << "[" << GetId() << "] Error while waiting for request: " << err << std::endl;
+            break;
+        }
+        if (!request) continue; //no error, but timeout
+        err = ProcessRequest(request);
+        if(err) {
+            std::cerr << "[" << GetId() << "] Error sending response: " << err << std::endl;
+            break;
+        }
+    }
+    io__->CloseSocket(socket_fd_, nullptr);
+    std::cout << "[" << GetId() << "] Disconnected." << std::endl;
+}
+
+
+std::unique_ptr<Request> Connection::WaitForNewRequest(Error* err) const noexcept {
+    //TODO: to be overwritten with MessagePack (or similar)
+    GenericNetworkRequestHeader generic_request_header;
+    io__->ReceiveWithTimeout(socket_fd_, &generic_request_header, sizeof(GenericNetworkRequestHeader), 50, err);
+    if(*err) {
+        if(*err == IOErrorTemplates::kTimeout) {
+            *err = nullptr;//Not an error in this case
+        }
+        return nullptr;
+    }
+    return request_factory__->GenerateRequest(generic_request_header, socket_fd_, err);
+}
+
+}
+
diff --git a/receiver/src/connection.h b/receiver/src/connection.h
new file mode 100644
index 0000000000000000000000000000000000000000..9861ca0d00cdce67138b6cf51f38c8881b94b953
--- /dev/null
+++ b/receiver/src/connection.h
@@ -0,0 +1,47 @@
+#ifndef HIDRA2_NetworkProducerPeerImpl_H
+#define HIDRA2_NetworkProducerPeerImpl_H
+
+#include "connection.h"
+
+#include <string>
+#include <map>
+#include <utility>
+#include <thread>
+#include <iostream>
+#include <atomic>
+#include <vector>
+
+#include "common/networking.h"
+#include "io/io.h"
+#include "request.h"
+
+namespace hidra2 {
+
+class Connection {
+  public:
+  private:
+    uint32_t connection_id_;
+    std::string address_;
+    int socket_fd_;
+  public:
+    static size_t kRequestHandlerMaxBufferSize;
+    static std::atomic<uint32_t> kNetworkProducerPeerImplGlobalCounter;
+
+    Connection(SocketDescriptor socket_fd, const std::string& address);
+    ~Connection() = default;
+
+    void Listen() const noexcept;
+    uint64_t GetId() const noexcept;
+
+    std::unique_ptr<RequestFactory> request_factory__;
+    std::unique_ptr<IO> io__;
+
+  private:
+    std::unique_ptr<Request> WaitForNewRequest(Error* err) const noexcept;
+    Error ProcessRequest(const std::unique_ptr<Request>& request) const noexcept;
+};
+
+}
+
+
+#endif //HIDRA2_NetworkProducerPeerImpl_H
diff --git a/receiver/src/main.cpp b/receiver/src/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3b871296c3a2838b2fc4561e5e01579380ae74cb
--- /dev/null
+++ b/receiver/src/main.cpp
@@ -0,0 +1,18 @@
+#include <iostream>
+#include "receiver.h"
+
+int main (int argc, char* argv[]) {
+    static const std::string address = "0.0.0.0:4200";
+
+    auto* receiver = new hidra2::Receiver();
+
+    hidra2::Error err;
+
+    std::cout << "Listening on " << address << std::endl;
+    receiver->Listen(address, &err);
+    if(err) {
+        std::cerr << "Failed to start receiver: " << err << std::endl;
+        return 1;
+    }
+    return 0;
+}
diff --git a/receiver/src/receiver.cpp b/receiver/src/receiver.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c614fd1e8856e282a5587c4c058c70fbae2c9c23
--- /dev/null
+++ b/receiver/src/receiver.cpp
@@ -0,0 +1,67 @@
+#include <cstring>
+#include <iostream>
+#include "receiver.h"
+#include "receiver_error.h"
+#include "connection.h"
+#include <io/io_factory.h>
+
+namespace hidra2 {
+
+
+const int Receiver::kMaxUnacceptedConnectionsBacklog = 5;
+
+Receiver::Receiver(): io__{GenerateDefaultIO()} {
+
+}
+
+Error Receiver::PrepareListener(std::string listener_address) {
+    Error err = nullptr;
+    listener_fd_  = io__->CreateAndBindIPTCPSocketListener(listener_address, kMaxUnacceptedConnectionsBacklog,
+                    &err);
+    return err;
+}
+
+
+void Receiver::Listen(std::string listener_address, Error* err, bool exit_after_first_connection) {
+    *err = PrepareListener(listener_address);
+    if(*err) {
+        return;
+    }
+
+    while(true) {
+        ProcessConnections(err);
+        if (exit_after_first_connection) break;
+    }
+}
+
+//TODO: remove error since it is not used
+void Receiver::ProcessConnections(Error* err) {
+    std::string address;
+    FileDescriptor connection_socket_fd;
+
+    //TODO: Use InetAcceptConnectionWithTimeout
+    auto client_info_tuple = io__->InetAcceptConnection(listener_fd_, err);
+    if(*err) {
+        //TODO: this can produce a lot of error messages
+        std::cerr << "An error occurred while accepting an incoming connection: " << err << std::endl;
+        return;
+    }
+    std::tie(address, connection_socket_fd) = *client_info_tuple;
+    StartNewConnectionInSeparateThread(connection_socket_fd, address);
+}
+
+void Receiver::StartNewConnectionInSeparateThread(int connection_socket_fd, const std::string& address)  {
+    auto thread = io__->NewThread([connection_socket_fd, address] {
+        auto connection = std::unique_ptr<Connection>(new Connection(connection_socket_fd, address));
+        std::cout << "[" << connection->GetId() << "] New connection from " << address << std::endl;
+        connection->Listen();
+    });
+
+    if (thread) {
+        thread->detach();
+    }
+    return;
+
+}
+
+}
\ No newline at end of file
diff --git a/receiver/src/receiver.h b/receiver/src/receiver.h
new file mode 100644
index 0000000000000000000000000000000000000000..a1da1fb4170b7a31a043992d5b0d6ec7ebfeff43
--- /dev/null
+++ b/receiver/src/receiver.h
@@ -0,0 +1,29 @@
+#ifndef HIDRA2_RECEIVER_H
+#define HIDRA2_RECEIVER_H
+
+#include <string>
+#include <thread>
+#include "connection.h"
+#include <list>
+
+namespace hidra2 {
+
+class Receiver {
+  private:
+    FileDescriptor listener_fd_ = -1;
+    Error PrepareListener(std::string listener_address);
+    void StartNewConnectionInSeparateThread(int connection_socket_fd, const std::string& address);
+    void ProcessConnections(Error* err);
+  public:
+    static const int kMaxUnacceptedConnectionsBacklog;//TODO: Read from config
+    Receiver(const Receiver&) = delete;
+    Receiver& operator=(const Receiver&) = delete;
+    Receiver();
+
+    void Listen(std::string listener_address, Error* err, bool exit_after_first_connection = false);
+    std::unique_ptr<IO> io__;
+};
+
+}
+
+#endif //HIDRA2_RECEIVER_H
diff --git a/receiver/src/receiver_error.h b/receiver/src/receiver_error.h
new file mode 100644
index 0000000000000000000000000000000000000000..42eb039d8e5720e23a98dfded74973b788233235
--- /dev/null
+++ b/receiver/src/receiver_error.h
@@ -0,0 +1,62 @@
+#ifndef HIDRA2_RECEIVER_ERROR_H
+#define HIDRA2_RECEIVER_ERROR_H
+
+#include "common/error.h"
+
+namespace hidra2 {
+
+enum class ReceiverErrorType {
+    kInvalidOpCode,
+    kBadRequest
+};
+
+//TODO Make a marco to create error class and error template class
+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::kReceiverError) {
+        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 kInvalidOpCode = ReceiverErrorTemplate {
+    "Invalid Opcode", ReceiverErrorType::kInvalidOpCode
+};
+auto const kBadRequest = ReceiverErrorTemplate {
+    "Bad request", ReceiverErrorType::kBadRequest
+};
+
+};
+}
+
+#endif //HIDRA2_RECEIVER_ERROR_H
diff --git a/receiver/src/request.cpp b/receiver/src/request.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7f38d168f1af06cc33e3efae9f3e96bd08a2f453
--- /dev/null
+++ b/receiver/src/request.cpp
@@ -0,0 +1,88 @@
+#include "request.h"
+#include "io/io_factory.h"
+
+namespace hidra2 {
+
+Request::Request(const GenericNetworkRequestHeader& header,
+                 SocketDescriptor socket_fd) : io__{GenerateDefaultIO()}, request_header_(header), socket_fd_{socket_fd} {
+}
+
+Error Request::AllocateDataBuffer() {
+    try {
+        data_buffer_.reset(new uint8_t[request_header_.data_size]);
+    } catch(std::exception& e) {
+        auto err = ErrorTemplates::kMemoryAllocationError.Generate();
+        err->Append(e.what());
+        return err;
+    }
+    return nullptr;
+}
+
+Error Request::ReceiveData() {
+    auto err = AllocateDataBuffer();
+    if (err) {
+        return err;
+    }
+    io__->Receive(socket_fd_, data_buffer_.get(), request_header_.data_size, &err);
+    return err;
+}
+
+
+Error Request::Handle() {
+    Error err;
+    if (request_header_.data_size != 0) {
+        auto err = ReceiveData();
+        if (err) {
+            return err;
+        }
+    }
+    for (auto handler : handlers_) {
+        auto err = handler->ProcessRequest(*this);
+        if (err) {
+            return err;
+        }
+    }
+    return nullptr;
+}
+
+const RequestHandlerList& Request::GetListHandlers() const {
+    return handlers_;
+}
+
+
+void Request::AddHandler(const RequestHandler* handler) {
+    handlers_.emplace_back(handler);
+}
+
+
+uint64_t Request::GetDataSize() const {
+    return request_header_.data_size;
+}
+
+const FileData& Request::GetData() const {
+    return data_buffer_;
+}
+
+std::string Request::GetFileName() const {
+    return std::to_string(request_header_.data_id) + ".bin";
+}
+
+
+std::unique_ptr<Request> RequestFactory::GenerateRequest(const GenericNetworkRequestHeader&
+        request_header, SocketDescriptor socket_fd,
+        Error* err) const noexcept {
+    *err = nullptr;
+    switch (request_header.op_code) {
+    case Opcode::kNetOpcodeSendData: {
+        auto request = std::unique_ptr<Request> {new Request{request_header, socket_fd}};
+        request->AddHandler(&request_handler_filewrite_);
+        return request;
+    }
+    default:
+        *err = ReceiverErrorTemplates::kInvalidOpCode.Generate();
+        return nullptr;
+    }
+
+}
+
+}
\ No newline at end of file
diff --git a/receiver/src/request.h b/receiver/src/request.h
new file mode 100644
index 0000000000000000000000000000000000000000..3d8ef1025dddc481ee9bd2dca594668f93367eab
--- /dev/null
+++ b/receiver/src/request.h
@@ -0,0 +1,45 @@
+#ifndef HIDRA2_REQUEST_H
+#define HIDRA2_REQUEST_H
+
+#include "receiver_error.h"
+#include "common/networking.h"
+#include "io/io.h"
+#include "request_handler.h"
+#include "request_handler_file_write.h"
+
+namespace hidra2 {
+
+using RequestHandlerList = std::vector<const RequestHandler*>;
+
+class Request {
+  public:
+    virtual Error Handle();
+    virtual ~Request() = default;
+    Request(const GenericNetworkRequestHeader& request_header, SocketDescriptor socket_fd);
+    void AddHandler(const RequestHandler*);
+    const RequestHandlerList& GetListHandlers() const;
+    virtual uint64_t GetDataSize() const;
+    virtual std::string GetFileName() const;
+
+    virtual const FileData& GetData() const;
+    std::unique_ptr<IO> io__;
+  private:
+    Error AllocateDataBuffer();
+    Error ReceiveData();
+    const GenericNetworkRequestHeader request_header_;
+    const SocketDescriptor socket_fd_;
+    FileData data_buffer_;
+    RequestHandlerList handlers_;
+};
+
+class RequestFactory {
+  public:
+    virtual std::unique_ptr<Request> GenerateRequest(const GenericNetworkRequestHeader& request_header,
+                                                     SocketDescriptor socket_fd, Error* err) const noexcept;
+  private:
+    RequestHandlerFileWrite request_handler_filewrite_;
+};
+
+}
+
+#endif //HIDRA2_REQUEST_H
diff --git a/receiver/src/request_handler.h b/receiver/src/request_handler.h
new file mode 100644
index 0000000000000000000000000000000000000000..2d208c636cf6eb8d3e8a62c961ecb6c2db054584
--- /dev/null
+++ b/receiver/src/request_handler.h
@@ -0,0 +1,19 @@
+#ifndef HIDRA2_REQUEST_HANDLER_H
+#define HIDRA2_REQUEST_HANDLER_H
+
+#include "receiver_error.h"
+
+namespace hidra2 {
+
+class Request;
+
+class RequestHandler {
+  public:
+    virtual Error ProcessRequest(const Request& request) const = 0;
+    virtual ~RequestHandler() = default;
+  private:
+};
+
+}
+
+#endif //HIDRA2_REQUEST_HANDLER_H
diff --git a/receiver/src/request_handler_file_write.cpp b/receiver/src/request_handler_file_write.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3b1a3c2bc4925502ed2789d3ac3e121f459edebb
--- /dev/null
+++ b/receiver/src/request_handler_file_write.cpp
@@ -0,0 +1,24 @@
+#include "request_handler_file_write.h"
+#include "io/io_factory.h"
+#include "request.h"
+namespace hidra2 {
+
+Error RequestHandlerFileWrite::ProcessRequest(const Request& request) const {
+    auto fsize = request.GetDataSize();
+    if (fsize <= 0 || fsize > kMaxFileSize) {
+        return ReceiverErrorTemplates::kBadRequest.Generate();
+    }
+
+    const FileData& data = request.GetData();
+
+    auto fname = request.GetFileName();
+//TODO: folder to write in config file
+    return io__->WriteDataToFile("files/" + fname, data, fsize);
+
+}
+
+RequestHandlerFileWrite::RequestHandlerFileWrite() : io__{GenerateDefaultIO()} {
+
+}
+
+}
diff --git a/receiver/src/request_handler_file_write.h b/receiver/src/request_handler_file_write.h
new file mode 100644
index 0000000000000000000000000000000000000000..8b9828ccd7310c98ea5d9ceaae4c66a4abb12d3f
--- /dev/null
+++ b/receiver/src/request_handler_file_write.h
@@ -0,0 +1,21 @@
+#ifndef HIDRA2_REQUEST_HANDLER_FILE_WRITE_H
+#define HIDRA2_REQUEST_HANDLER_FILE_WRITE_H
+
+#include "request_handler.h"
+
+#include "io/io.h"
+
+namespace hidra2 {
+
+const uint64_t kMaxFileSize = uint64_t(1024) * 1024 * 1024 * 2; //2GB
+
+class RequestHandlerFileWrite final: public RequestHandler {
+  public:
+    RequestHandlerFileWrite();
+    Error ProcessRequest(const Request& request) const override;
+    std::unique_ptr<IO> io__;
+};
+
+}
+
+#endif //HIDRA2_REQUEST_HANDLER_FILE_WRITE_H
diff --git a/receiver/unittests/test_connection.cpp b/receiver/unittests/test_connection.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..846e6df26be5d0283e761d1d1d73cdd54765b18e
--- /dev/null
+++ b/receiver/unittests/test_connection.cpp
@@ -0,0 +1,183 @@
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+#include <unittests/MockIO.h>
+#include "../src/connection.h"
+#include "../src/receiver_error.h"
+#include "../src/request.h"
+
+using ::testing::Test;
+using ::testing::Return;
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::SetArgReferee;
+using ::testing::Gt;
+using ::testing::Eq;
+using ::testing::Mock;
+using ::testing::NiceMock;
+using ::testing::SaveArg;
+using ::testing::SaveArgPointee;
+using ::testing::InSequence;
+using ::testing::SetArgPointee;
+using ::hidra2::Error;
+using ::hidra2::ErrorInterface;
+using ::hidra2::FileDescriptor;
+using ::hidra2::SocketDescriptor;
+using ::hidra2::GenericNetworkRequestHeader;
+using ::hidra2::SendDataResponse;
+using ::hidra2::GenericNetworkRequestHeader;
+using ::hidra2::GenericNetworkResponse;
+using ::hidra2::Opcode;
+using ::hidra2::Connection;
+using ::hidra2::MockIO;
+using hidra2::Request;
+
+namespace {
+
+class MockRequest: public Request {
+  public:
+    MockRequest(const GenericNetworkRequestHeader& request_header, SocketDescriptor socket_fd):
+        Request(request_header, socket_fd) {};
+    Error Handle() override {
+        return Error{Handle_t()};
+    };
+    MOCK_CONST_METHOD0(Handle_t, ErrorInterface * ());
+};
+
+class MockRequestFactory: public hidra2::RequestFactory {
+  public:
+    std::unique_ptr<Request> GenerateRequest(const GenericNetworkRequestHeader& request_header,
+                                             SocketDescriptor socket_fd,
+                                             Error* err) const noexcept override {
+        ErrorInterface* error = nullptr;
+        auto res = GenerateRequest_t(request_header, socket_fd, &error);
+        err->reset(error);
+        return std::unique_ptr<Request> {res};
+    }
+
+    MOCK_CONST_METHOD3(GenerateRequest_t, Request * (const GenericNetworkRequestHeader&,
+                                                     SocketDescriptor socket_fd,
+                                                     ErrorInterface**));
+
+};
+
+class ConnectionTests : public Test {
+  public:
+    Connection connection{0, "some_address"};
+    MockIO mock_io;
+    MockRequestFactory mock_factory;
+    void SetUp() override {
+        connection.io__ = std::unique_ptr<hidra2::IO> {&mock_io};;
+        connection.request_factory__ = std::unique_ptr<hidra2::RequestFactory> {&mock_factory};
+        ON_CALL(mock_io, ReceiveWithTimeout_t(_, _, _, _, _)).
+        WillByDefault(DoAll(testing::SetArgPointee<4>(nullptr),
+                            testing::Return(0)));
+        EXPECT_CALL(mock_io, CloseSocket_t(_, _));
+
+    }
+    void TearDown() override {
+        connection.io__.release();
+        connection.request_factory__.release();
+    }
+
+};
+
+
+TEST_F(ConnectionTests, ErrorWaitForNewRequest) {
+
+    EXPECT_CALL(mock_io, ReceiveWithTimeout_t(_, _, _, _, _)).Times(2).
+    WillOnce(
+        DoAll(SetArgPointee<4>(new hidra2::IOError("", hidra2::IOErrorType::kTimeout)),
+              Return(0)))
+    .WillOnce(
+        DoAll(SetArgPointee<4>(new hidra2::IOError("", hidra2::IOErrorType::kUnknownIOError)),
+              Return(0))
+    );
+
+    connection.Listen();
+}
+
+ACTION_P(SaveArg1ToGenericNetworkResponse, value) {
+    auto resp =  *static_cast<const GenericNetworkResponse*>(arg1);
+    value->error_code = resp.error_code;
+}
+
+
+TEST_F(ConnectionTests, CallsHandleRequest) {
+
+    GenericNetworkRequestHeader header;
+    auto request = new MockRequest{header, 1};
+
+    EXPECT_CALL(mock_io, ReceiveWithTimeout_t(_, _, _, _, _));
+
+    EXPECT_CALL(mock_factory, GenerateRequest_t(_, _, _)).WillOnce(
+        Return(request)
+    );
+
+    EXPECT_CALL(*request, Handle_t()).WillOnce(
+        Return(new hidra2::SimpleError{""})
+    );
+
+    EXPECT_CALL(mock_io, Send_t(_, _, _, _)).WillOnce(
+        DoAll(SetArgPointee<3>(new hidra2::IOError("Test Send Error", hidra2::IOErrorType::kUnknownIOError)),
+              Return(0)
+             ));
+
+
+    connection.Listen();
+}
+
+TEST_F(ConnectionTests, SendsNoErrorToProducer) {
+
+    GenericNetworkRequestHeader header;
+    auto request = new MockRequest{header, 1};
+
+    EXPECT_CALL(mock_io, ReceiveWithTimeout_t(_, _, _, _, _));
+
+    EXPECT_CALL(mock_factory, GenerateRequest_t(_, _, _)).WillOnce(
+        Return(request)
+    );
+
+    EXPECT_CALL(*request, Handle_t()).WillOnce(
+        Return(nullptr)
+    );
+    GenericNetworkResponse response;
+    EXPECT_CALL(mock_io, Send_t(_, _, sizeof(GenericNetworkResponse), _)).WillOnce(
+        DoAll(SetArgPointee<3>(new hidra2::IOError("Test Send Error", hidra2::IOErrorType::kUnknownIOError)),
+              SaveArg1ToGenericNetworkResponse(&response),
+              Return(0)
+             ));
+
+    connection.Listen();
+
+    ASSERT_THAT(response.error_code, Eq(hidra2::NetworkErrorCode::kNetErrorNoError));
+}
+
+TEST_F(ConnectionTests, SendsErrorToProducer) {
+
+    GenericNetworkRequestHeader header;
+    auto request = new MockRequest{header, 1};
+
+    EXPECT_CALL(mock_io, ReceiveWithTimeout_t(_, _, _, _, _));
+
+    EXPECT_CALL(mock_factory, GenerateRequest_t(_, _, _)).WillOnce(
+        Return(request)
+    );
+
+    EXPECT_CALL(*request, Handle_t()).WillOnce(
+        Return(new hidra2::SimpleError{""})
+    );
+
+    GenericNetworkResponse response;
+    EXPECT_CALL(mock_io, Send_t(_, _, sizeof(GenericNetworkResponse), _)).WillOnce(
+        DoAll(SetArgPointee<3>(new hidra2::IOError("Test Send Error", hidra2::IOErrorType::kUnknownIOError)),
+              SaveArg1ToGenericNetworkResponse(&response),
+              Return(0)
+             ));
+
+    connection.Listen();
+
+    ASSERT_THAT(response.error_code, Eq(hidra2::NetworkErrorCode::kNetErrorInternalServerError));
+
+}
+
+}
diff --git a/receiver/unittests/test_receiver.cpp b/receiver/unittests/test_receiver.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0226b182bbfca0afb5f0eccdf5ebe89befad3075
--- /dev/null
+++ b/receiver/unittests/test_receiver.cpp
@@ -0,0 +1,94 @@
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+#include <unittests/MockIO.h>
+#include "../src/receiver.h"
+#include "../src/receiver_error.h"
+#include "../src/connection.h"
+
+using ::testing::Return;
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::SetArgReferee;
+using ::testing::SetArgPointee;
+using ::testing::Gt;
+using ::testing::Eq;
+using ::testing::Mock;
+using ::testing::InSequence;
+using ::hidra2::Error;
+using ::hidra2::FileDescriptor;
+using ::hidra2::ErrorInterface;
+using ::hidra2::Connection;
+using ::hidra2::SocketDescriptor;
+
+namespace {
+
+class StartListenerFixture : public testing::Test {
+  public:
+    const hidra2::SocketDescriptor expected_socket_descriptor = 20;
+    const hidra2::SocketDescriptor expected_socket_descriptor_client = 23;
+    const std::string expected_address = "somehost:13579";
+    const uint64_t expected_file_id = 314322;
+    const uint64_t expected_file_size = 784387;
+    const FileDescriptor expected_fd = 12643;
+
+    Error err;
+
+    ::testing::NiceMock<hidra2::MockIO> mock_io;
+    hidra2::Receiver receiver;
+
+    void SetUp() override {
+        err = nullptr;
+        receiver.io__ = std::unique_ptr<hidra2::IO> {&mock_io};
+    }
+    void TearDown() override {
+        receiver.io__.release();
+    }
+
+
+};
+
+TEST_F(StartListenerFixture, CreateAndBindIPTCPSocketListenerError) {
+    EXPECT_CALL(mock_io, CreateAndBindIPTCPSocketListener_t(expected_address, receiver.kMaxUnacceptedConnectionsBacklog, _))
+    .WillOnce(DoAll(
+                  SetArgPointee<2>(hidra2::IOErrorTemplates::kUnknownIOError.Generate().release()),
+                  Return(0)
+              ));
+
+    receiver.Listen(expected_address, &err, true);
+
+    ASSERT_THAT(err, Eq(hidra2::IOErrorTemplates::kUnknownIOError));
+}
+
+
+TEST_F(StartListenerFixture, InetAcceptConnectionError) {
+    EXPECT_CALL(mock_io, InetAcceptConnection_t(_, _))
+    .WillOnce(DoAll(
+                  SetArgPointee<1>(hidra2::IOErrorTemplates::kUnknownIOError.Generate().release()),
+                  Return(new std::tuple<std::string, SocketDescriptor>(expected_address, expected_socket_descriptor_client))
+              ));
+
+    receiver.Listen(expected_address, &err, true);
+
+    ASSERT_THAT(err, Eq(hidra2::IOErrorTemplates::kUnknownIOError));
+}
+
+TEST_F(StartListenerFixture, Ok) {
+
+    EXPECT_CALL(mock_io, InetAcceptConnection_t(_, _))
+    .WillOnce(DoAll(
+                  SetArgPointee<1>(nullptr),
+                  Return(new std::tuple<std::string, SocketDescriptor>(expected_address, expected_socket_descriptor_client))
+              ));
+
+    EXPECT_CALL(mock_io, NewThread_t(_)).
+    WillOnce(
+        Return(nullptr)
+    );
+
+    receiver.Listen(expected_address, &err, true);
+
+    ASSERT_THAT(err, Eq(nullptr));
+}
+
+
+}
diff --git a/receiver/unittests/test_request.cpp b/receiver/unittests/test_request.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9b263826fe308534afd922688f6a64cf2311619e
--- /dev/null
+++ b/receiver/unittests/test_request.cpp
@@ -0,0 +1,175 @@
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+#include <unittests/MockIO.h>
+#include "../src/connection.h"
+#include "../src/receiver_error.h"
+#include "../src/request.h"
+#include "../src/request_handler.h"
+#include "../src/request_handler_file_write.h"
+
+using ::testing::Test;
+using ::testing::Return;
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::SetArgReferee;
+using ::testing::Gt;
+using ::testing::Eq;
+using ::testing::Ne;
+using ::testing::Mock;
+using ::testing::NiceMock;
+using ::testing::InSequence;
+using ::testing::SetArgPointee;
+using ::hidra2::Error;
+using ::hidra2::ErrorInterface;
+using ::hidra2::FileDescriptor;
+using ::hidra2::SocketDescriptor;
+using ::hidra2::GenericNetworkRequestHeader;
+using ::hidra2::SendDataResponse;
+using ::hidra2::GenericNetworkRequestHeader;
+using ::hidra2::GenericNetworkResponse;
+using ::hidra2::Opcode;
+using ::hidra2::Connection;
+using ::hidra2::MockIO;
+using hidra2::Request;
+
+namespace {
+
+class MockReqestHandler : public hidra2::RequestHandler {
+  public:
+    Error ProcessRequest(const Request& request) const override {
+        return Error{ProcessRequest_t(request)};
+    }
+
+    MOCK_CONST_METHOD1(ProcessRequest_t, ErrorInterface * (const Request& request));
+
+};
+
+class FactoryTests : public Test {
+  public:
+    hidra2::RequestFactory factory;
+    Error err{nullptr};
+    GenericNetworkRequestHeader generic_request_header;
+    void SetUp() override {
+    }
+    void TearDown() override {
+    }
+};
+
+TEST_F(FactoryTests, ErrorOnWrongCode) {
+    generic_request_header.op_code = hidra2::Opcode::kNetOpcodeUnknownOp;
+    auto request = factory.GenerateRequest(generic_request_header, 1, &err);
+
+    ASSERT_THAT(err, Ne(nullptr));
+}
+
+TEST_F(FactoryTests, ReturnsDataRequestOnkNetOpcodeSendDataCode) {
+    generic_request_header.op_code = hidra2::Opcode::kNetOpcodeSendData;
+    auto request = factory.GenerateRequest(generic_request_header, 1, &err);
+
+    ASSERT_THAT(err, Eq(nullptr));
+    ASSERT_THAT(dynamic_cast<hidra2::Request*>(request.get()), Ne(nullptr));
+    ASSERT_THAT(dynamic_cast<const hidra2::RequestHandlerFileWrite*>(request->GetListHandlers()[0]), Ne(nullptr));
+}
+
+
+
+
+class RequestTests : public Test {
+  public:
+    GenericNetworkRequestHeader generic_request_header;
+    hidra2::SocketDescriptor socket_fd_{1};
+    uint64_t data_size_ {100};
+    uint64_t data_id_{15};
+    std::unique_ptr<Request> request;
+    NiceMock<MockIO> mock_io;
+    void SetUp() override {
+        generic_request_header.data_size = data_size_;
+        generic_request_header.data_id = data_id_;
+        request.reset(new Request{generic_request_header, socket_fd_});
+        request->io__ = std::unique_ptr<hidra2::IO> {&mock_io};
+        ON_CALL(mock_io, Receive_t(socket_fd_, _, data_size_, _)).WillByDefault(
+            DoAll(SetArgPointee<3>(nullptr),
+                  Return(0)
+                 ));
+    }
+    void TearDown() override {
+        request->io__.release();
+    }
+
+};
+
+TEST_F(RequestTests, HandleDoesNotReceiveEmptyData) {
+    generic_request_header.data_size = 0;
+    request->io__.release();
+    request.reset(new Request{generic_request_header, socket_fd_});
+    request->io__ = std::unique_ptr<hidra2::IO> {&mock_io};;
+
+    EXPECT_CALL(mock_io, Receive_t(_, _, _, _)).Times(0);
+
+    auto err = request->Handle();
+
+    ASSERT_THAT(err, Eq(nullptr));
+}
+
+TEST_F(RequestTests, HandleReturnsErrorOnDataReceive) {
+    EXPECT_CALL(mock_io, Receive_t(socket_fd_, _, data_size_, _)).WillOnce(
+        DoAll(SetArgPointee<3>(new hidra2::IOError("Test Read Error", hidra2::IOErrorType::kReadError)),
+              Return(0)
+             ));
+
+    auto err = request->Handle();
+    ASSERT_THAT(err, Eq(hidra2::IOErrorTemplates::kReadError));
+}
+
+
+TEST_F(RequestTests, HandleProcessesRequests) {
+
+    MockReqestHandler mock_request_handler;
+
+    EXPECT_CALL(mock_request_handler, ProcessRequest_t(_)).WillOnce(
+        Return(nullptr)
+    ).WillOnce(
+        Return(new hidra2::IOError("Test Send Error", hidra2::IOErrorType::kUnknownIOError))
+    );;
+
+    request->AddHandler(&mock_request_handler);
+    request->AddHandler(&mock_request_handler);
+
+    auto err = request->Handle();
+
+    ASSERT_THAT(err, Eq(hidra2::IOErrorTemplates::kUnknownIOError));
+}
+
+TEST_F(RequestTests, DataIsNullAtInit) {
+    auto& data = request->GetData();
+
+    ASSERT_THAT(data, Eq(nullptr));
+}
+
+TEST_F(RequestTests, GetDataIsNotNullptr) {
+
+    request->Handle();
+    auto& data = request->GetData();
+
+
+    ASSERT_THAT(data, Ne(nullptr));
+
+
+}
+
+
+TEST_F(RequestTests, GetDataSize) {
+    auto size = request->GetDataSize();
+
+    ASSERT_THAT(size, Eq(data_size_));
+}
+
+TEST_F(RequestTests, GetFileName) {
+    auto fname = request->GetFileName();
+    auto s = std::to_string(data_id_) + ".bin";
+
+    ASSERT_THAT(fname, Eq(s));
+}
+
+
+}
diff --git a/receiver/unittests/test_request_handler_file_write.cpp b/receiver/unittests/test_request_handler_file_write.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7c3dc1d09a1f0cc8396cd961e1c5ac7de93a986d
--- /dev/null
+++ b/receiver/unittests/test_request_handler_file_write.cpp
@@ -0,0 +1,113 @@
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+#include <unittests/MockIO.h>
+#include "../src/receiver_error.h"
+#include "../src/request.h"
+#include "../src/request_handler.h"
+#include "../src/request_handler_file_write.h"
+#include "common/networking.h"
+
+using ::testing::Test;
+using ::testing::Return;
+using ::testing::ReturnRef;
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::SetArgReferee;
+using ::testing::Gt;
+using ::testing::Eq;
+using ::testing::Ne;
+using ::testing::Mock;
+using ::testing::NiceMock;
+using ::testing::InSequence;
+using ::testing::SetArgPointee;
+using ::hidra2::Error;
+using ::hidra2::ErrorInterface;
+using ::hidra2::FileDescriptor;
+using ::hidra2::SocketDescriptor;
+using ::hidra2::MockIO;
+using hidra2::Request;
+using hidra2::RequestHandlerFileWrite;
+using ::hidra2::GenericNetworkRequestHeader;
+
+namespace {
+
+class MockRequest: public Request {
+  public:
+    MockRequest(const GenericNetworkRequestHeader& request_header, SocketDescriptor socket_fd):
+        Request(request_header, socket_fd) {};
+
+    MOCK_CONST_METHOD0(GetFileName, std::string());
+    MOCK_CONST_METHOD0(GetDataSize, uint64_t());
+    MOCK_CONST_METHOD0(GetData, const hidra2::FileData & ());
+};
+
+class FileWriteHandlerTests : public Test {
+  public:
+    RequestHandlerFileWrite handler;
+    NiceMock<MockIO> mock_io;
+    std::unique_ptr<MockRequest> mock_request;
+    void SetUp() override {
+        GenericNetworkRequestHeader request_header;
+        request_header.data_id = 2;
+        mock_request.reset(new MockRequest{request_header, 1});
+        handler.io__ = std::unique_ptr<hidra2::IO> {&mock_io};
+        /*      ON_CALL(mock_io, Receive_t(socket_fd_, _, data_size_, _)).WillByDefault(
+                  DoAll(SetArgPointee<3>(nullptr),
+                        Return(0)
+                  ));*/
+    }
+    void TearDown() override {
+        handler.io__.release();
+    }
+
+};
+
+TEST_F(FileWriteHandlerTests, ErrorWhenZeroFileSize) {
+    EXPECT_CALL(*mock_request, GetDataSize())
+    .WillOnce(Return(0))
+    ;
+
+    auto err = handler.ProcessRequest(*mock_request);
+
+    ASSERT_THAT(err, Eq(hidra2::ReceiverErrorTemplates::kBadRequest));
+}
+
+TEST_F(FileWriteHandlerTests, ErrorWhenTooBigFileSize) {
+    EXPECT_CALL(*mock_request, GetDataSize())
+    .WillOnce(Return(hidra2::kMaxFileSize + 1))
+    ;
+
+    auto err = handler.ProcessRequest(*mock_request);
+
+    ASSERT_THAT(err, Eq(hidra2::ReceiverErrorTemplates::kBadRequest));
+}
+
+TEST_F(FileWriteHandlerTests, CallsWriteFile) {
+    std::string expected_file_name = "2.bin";
+    uint64_t expected_file_size = 10;
+    EXPECT_CALL(*mock_request, GetDataSize())
+    .WillOnce(Return(expected_file_size))
+    ;
+
+    hidra2::FileData data;
+    EXPECT_CALL(*mock_request, GetData())
+    .WillOnce(ReturnRef(data))
+    ;
+
+    EXPECT_CALL(*mock_request, GetFileName())
+    .WillOnce(Return(expected_file_name))
+    ;
+
+
+    EXPECT_CALL(mock_io, WriteDataToFile_t("files/" + expected_file_name, _, expected_file_size))
+    .WillOnce(
+        Return(hidra2::IOErrorTemplates::kUnknownIOError.Generate().release())
+    );
+
+    auto err = handler.ProcessRequest(*mock_request);
+
+    ASSERT_THAT(err, Eq(hidra2::IOErrorTemplates::kUnknownIOError));
+}
+
+
+}
\ No newline at end of file
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 47f40c7bca39f70f88fe1b8a0a8d38e46fecc111..3e431d34cd6ac7e59e99566ff0151bea49a95dbf 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -1,3 +1,4 @@
 add_subdirectory(automatic)
 
 
+
diff --git a/tests/automatic/CMakeLists.txt b/tests/automatic/CMakeLists.txt
index 0fb7141827c5997da8294a401a2bb2a3721a238e..1c613b8555c478cc08aacf1db994443192bbe1b5 100644
--- a/tests/automatic/CMakeLists.txt
+++ b/tests/automatic/CMakeLists.txt
@@ -19,3 +19,4 @@ endif()
 add_subdirectory(worker)
 
 
+add_subdirectory(producer_receiver)
\ No newline at end of file
diff --git a/tests/automatic/common/cpp/CMakeLists.txt b/tests/automatic/common/cpp/CMakeLists.txt
index 1eec82d9fb06edce8549838ed1a56c15b5a20f45..520d0153db6a34e18e9aeaf68448af3dfe6c0b5e 100644
--- a/tests/automatic/common/cpp/CMakeLists.txt
+++ b/tests/automatic/common/cpp/CMakeLists.txt
@@ -8,3 +8,7 @@ set(SOURCE_FILES
 add_library(${TARGET_NAME} STATIC ${SOURCE_FILES})
 target_include_directories(${TARGET_NAME} PUBLIC include)
 set_target_properties(${TARGET_NAME} PROPERTIES LINKER_LANGUAGE CXX)
+
+#Add all necessary common libraries
+GET_PROPERTY(HIDRA2_COMMON_IO_LIBRARIES GLOBAL PROPERTY HIDRA2_COMMON_IO_LIBRARIES)
+target_link_libraries(${TARGET_NAME} ${HIDRA2_COMMON_IO_LIBRARIES})
diff --git a/tests/automatic/producer_receiver/CMakeLists.txt b/tests/automatic/producer_receiver/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c4da20d000bc7375e799fcd9b063a640d75c506a
--- /dev/null
+++ b/tests/automatic/producer_receiver/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(transfer_single_file)
diff --git a/tests/automatic/producer_receiver/transfer_single_file/CMakeLists.txt b/tests/automatic/producer_receiver/transfer_single_file/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..83a9f59580c5427848720b28aea7353d86335d23
--- /dev/null
+++ b/tests/automatic/producer_receiver/transfer_single_file/CMakeLists.txt
@@ -0,0 +1,6 @@
+set(TARGET_NAME transfer-single-file)
+
+################################
+# Testing
+################################
+add_script_test("${TARGET_NAME}" "$<TARGET_FILE:dummy-data-producer> $<TARGET_FILE:receiver-bin>" nomem)
diff --git a/tests/automatic/producer_receiver/transfer_single_file/check_linux.sh b/tests/automatic/producer_receiver/transfer_single_file/check_linux.sh
new file mode 100644
index 0000000000000000000000000000000000000000..163d4ab08b8144ea133ca0f6f48899b304234e63
--- /dev/null
+++ b/tests/automatic/producer_receiver/transfer_single_file/check_linux.sh
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+
+set -e
+
+trap Cleanup EXIT
+
+Cleanup() {
+	echo cleanup
+    kill $receiverid
+	rm -rf files
+}
+
+nohup $2 &>/dev/null &
+sleep 0.3
+receiverid=`echo $!`
+
+mkdir files
+
+$1 localhost:4200 100 1
+
+ls -ln files/0.bin | awk '{ print $5 }'| grep 100
diff --git a/tests/automatic/producer_receiver/transfer_single_file/check_windows.bat b/tests/automatic/producer_receiver/transfer_single_file/check_windows.bat
new file mode 100644
index 0000000000000000000000000000000000000000..9413a82a228200e5a50ed87135e10450ab471714
--- /dev/null
+++ b/tests/automatic/producer_receiver/transfer_single_file/check_windows.bat
@@ -0,0 +1,28 @@
+set full_recv_name="%2"
+set short_recv_name="%~nx2"
+
+start /B "" "%full_recv_name%"
+
+ping 1.0.0.0 -n 1 -w 100 > nul
+
+mkdir files
+
+%1 localhost:4200 100 1
+
+ping 1.0.0.0 -n 1 -w 100 > nul
+
+FOR /F "usebackq" %%A IN ('files\0.bin') DO set size=%%~zA
+
+if %size% NEQ 100 goto :error
+
+goto :clean
+
+:error
+call :clean
+exit /b 1
+
+:clean
+Taskkill /IM "%short_recv_name%" /F
+rmdir /S /Q files
+
+
diff --git a/tests/automatic/system_io/CMakeLists.txt b/tests/automatic/system_io/CMakeLists.txt
index 60be4b4c07fa5d1f9e8224a79a4f6a847c0d5600..84f9db59c371ee52ea4dc29e0a56f25e18a6cba2 100644
--- a/tests/automatic/system_io/CMakeLists.txt
+++ b/tests/automatic/system_io/CMakeLists.txt
@@ -3,4 +3,6 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.7) # needed for fixtures
 add_subdirectory(read_folder_content)
 add_subdirectory(read_file_content)
 add_subdirectory(read_string_from_file)
-
+add_subdirectory(ip_tcp_network)
+add_subdirectory(resolve_hostname_to_ip)
+add_subdirectory(write_data_to_file)
diff --git a/tests/automatic/system_io/ip_tcp_network/CMakeLists.txt b/tests/automatic/system_io/ip_tcp_network/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..cbe323ad4a425bdbbc7431e1c22198616034098d
--- /dev/null
+++ b/tests/automatic/system_io/ip_tcp_network/CMakeLists.txt
@@ -0,0 +1,16 @@
+set(TARGET_NAME ip_tcp_network)
+set(SOURCE_FILES ip_tcp_network.cpp)
+
+################################
+# Executable and link
+################################
+add_executable(${TARGET_NAME} ${SOURCE_FILES} $<TARGET_OBJECTS:system_io> )
+target_link_libraries(${TARGET_NAME} test_common)
+target_include_directories(${TARGET_NAME} PUBLIC ${HIDRA2_CXX_COMMON_INCLUDE_DIR})
+set_target_properties(${TARGET_NAME} PROPERTIES LINKER_LANGUAGE CXX)
+
+################################
+# Testing
+################################
+# memory test too slow
+add_integration_test(${TARGET_NAME} ip_tcp_network " " nomem)
diff --git a/tests/automatic/system_io/ip_tcp_network/ip_tcp_network.cpp b/tests/automatic/system_io/ip_tcp_network/ip_tcp_network.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a38a459eb1d69e128f3e2a9ee0067f7bcc0e9e94
--- /dev/null
+++ b/tests/automatic/system_io/ip_tcp_network/ip_tcp_network.cpp
@@ -0,0 +1,183 @@
+#include <iostream>
+#include "io/io_factory.h"
+#include <chrono>
+#include <thread>
+#include <future>
+
+#include "testing.h"
+
+using hidra2::Error;
+using hidra2::ErrorType;
+using hidra2::AddressFamilies;
+using hidra2::SocketTypes;
+using hidra2::SocketProtocols;
+using hidra2::FileDescriptor;
+using hidra2::M_AssertEq;
+
+using namespace std::chrono;
+
+static const std::unique_ptr<hidra2::IO> io(hidra2::GenerateDefaultIO());
+static const std::string kListenAddress = "127.0.0.1:60123";
+static std::promise<void> kThreadStarted;
+static const int kNumberOfChecks = 2;
+static const size_t kSkipAmount = 500;
+
+void Exit(int exit_number) {
+    std::cerr << "ERROR: Exit on " << exit_number << std::endl;
+    exit(exit_number);
+}
+
+void ExitIfErrIsNotOk(Error* err, int exit_number) {
+    if(*err != nullptr) {
+        std::cerr << "Explain(): " << (*err)->Explain() << std::endl;
+        Exit(exit_number);
+    }
+}
+
+std::unique_ptr<std::thread> CreateEchoServerThread() {
+    return io->NewThread([&] {
+        Error err;
+        FileDescriptor socket = io->CreateSocket(AddressFamilies::INET, SocketTypes::STREAM, SocketProtocols::IP, &err);
+        ExitIfErrIsNotOk(&err, 100);
+        io->InetBind(socket, kListenAddress, &err);
+        std::cout << "[SERVER] Listen" << std::endl;
+        ExitIfErrIsNotOk(&err, 101);
+        io->Listen(socket, 5, &err);
+        ExitIfErrIsNotOk(&err, 102);
+        kThreadStarted.set_value();
+
+        for(int i = 0; i < kNumberOfChecks; i++) {
+            std::cout << "[SERVER][" << i << "] InetAcceptConnection" << std::endl;
+            auto client_info_tuple = io->InetAcceptConnection(socket, &err);
+            ExitIfErrIsNotOk(&err, 103);
+            std::string client_address;
+            FileDescriptor client_fd;
+            std::tie(client_address, client_fd) = *client_info_tuple;
+
+            ExitIfErrIsNotOk(&err, 104);
+            while (true) {
+                uint64_t need_to_receive_size;
+                io->ReceiveWithTimeout(client_fd, &need_to_receive_size, sizeof(uint64_t), 100, &err);
+                if(err != nullptr) {
+                    if (hidra2::IOErrorTemplates::kTimeout == err) {
+                        continue;
+                    }
+                    if (hidra2::ErrorTemplates::kEndOfFile == err) {
+                        break;
+                    }
+                }
+                ExitIfErrIsNotOk(&err, 105);//ReceiveWithTimeout
+
+                std::unique_ptr<uint8_t[]> buffer(new uint8_t[need_to_receive_size]);
+
+                io->Skip(client_fd, kSkipAmount, &err);
+                ExitIfErrIsNotOk(&err, 106);
+
+                size_t received = io->Receive(client_fd, buffer.get(), need_to_receive_size, &err);
+                io->Send(client_fd, buffer.get(), received, &err);
+                ExitIfErrIsNotOk(&err, 107);
+            }
+
+            std::cout << "[SERVER][" << i << "] Close client_fd" << std::endl;
+            io->CloseSocket(client_fd, &err);
+            ExitIfErrIsNotOk(&err, 108);
+        }
+        std::cout << "[SERVER] Close server socket" << std::endl;
+        io->CloseSocket(socket, &err);
+        ExitIfErrIsNotOk(&err, 109);
+    });
+}
+
+void CheckNormal(int times, size_t size) {
+    Error err;
+    std::cout << "[CLIENT] CreateAndConnectIPTCPSocket" << std::endl;
+    FileDescriptor socket = io->CreateAndConnectIPTCPSocket(kListenAddress, &err);
+    ExitIfErrIsNotOk(&err, 201);
+
+    std::cout << "[CLIENT] ReceiveWithTimeout" << std::endl;
+    io->ReceiveWithTimeout(socket, nullptr, 1, 1000 * 100/*100ms*/, &err);
+    if (hidra2::IOErrorTemplates::kTimeout != err) {
+        ExitIfErrIsNotOk(&err, 202);
+    }
+
+    for (int i = 0; i < times; i++) {
+        std::cout << "[CLIENT] Allocate and create random numbers" << std::endl;
+        std::unique_ptr<uint8_t[]> buffer(new uint8_t[size]);
+        for (size_t i = 0; i < size; i++) {
+            buffer[i] = rand();
+        }
+
+        uint64_t send_size = size;
+
+        std::cout << "[CLIENT] Send Size" << std::endl;
+        io->Send(socket, &send_size, sizeof(uint64_t), &err);
+        ExitIfErrIsNotOk(&err, 203);
+
+        std::cout << "[CLIENT] Send data to skip" << std::endl;
+        io->Send(socket, buffer.get(), kSkipAmount, &err);
+        ExitIfErrIsNotOk(&err, 204);
+
+        std::cout << "[CLIENT] Send" << std::endl;
+        io->Send(socket, buffer.get(), size, &err);
+        ExitIfErrIsNotOk(&err, 205);
+
+        std::unique_ptr<uint8_t[]> buffer2(new uint8_t[size]);
+        std::cout << "[CLIENT] Receive" << std::endl;
+        size_t receive_count = io->Receive(socket, buffer2.get(), size, &err);
+        ExitIfErrIsNotOk(&err, 206);
+        if(receive_count != size) {
+            Exit(205);
+        }
+
+        std::cout << "[CLIENT] buffer check" << std::endl;
+        for (size_t i = 0; i < size; i++) {
+            if (buffer[i] != buffer2[i]) {
+                Exit(207);
+            }
+        }
+    }
+
+    std::cout << "[CLIENT] Close" << std::endl;
+    io->CloseSocket(socket, &err);
+    ExitIfErrIsNotOk(&err, 108);
+}
+
+int main(int argc, char* argv[]) {
+    Error err;
+    std::cout << "[META] Check if connection is refused if server is not running" << std::endl;
+    io->CreateAndConnectIPTCPSocket(kListenAddress, &err);
+    if(hidra2::IOErrorTemplates::kConnectionRefused != err) {
+        ExitIfErrIsNotOk(&err, 301);
+    }
+
+    std::cout << "[META] Check invalid address format - Missing port" << std::endl;
+    io->CreateAndConnectIPTCPSocket("localhost", &err);
+    if(hidra2::IOErrorTemplates::kInvalidAddressFormat != err) {
+        ExitIfErrIsNotOk(&err, 302);
+    }
+
+    std::cout << "[META] Check unknown host" << std::endl;
+    io->CreateAndConnectIPTCPSocket("some-host-that-might-not-exists.aa:1234", &err);
+    if(hidra2::IOErrorTemplates::kUnableToResolveHostname != err) {
+        ExitIfErrIsNotOk(&err, 303);
+    }
+
+    std::unique_ptr<std::thread> server_thread = CreateEchoServerThread();
+    kThreadStarted.get_future().get();//Make sure that the server is started
+
+    std::cout << "Check 1" << std::endl;
+    CheckNormal(10, 1024 * 1024 * 3);//3 MiByte
+    std::cout << "Check 2" << std::endl;
+    CheckNormal(30, 1024);//1 KiByte
+
+    std::cout << "server_thread->join()" << std::endl;
+    server_thread->join();
+
+    std::cout << "[META] Check if connection is refused after server is closed" << std::endl;
+    io->CreateAndConnectIPTCPSocket(kListenAddress, &err);
+    if(hidra2::IOErrorTemplates::kConnectionRefused != err) {
+        ExitIfErrIsNotOk(&err, 304);
+    }
+
+    return 0;
+}
diff --git a/tests/automatic/system_io/read_file_content/CMakeLists.txt b/tests/automatic/system_io/read_file_content/CMakeLists.txt
index 253fc7d58fbd0255f5d12b38c8374a2b6810570c..c65eb453715599a2237d6097832c420af90bbad0 100644
--- a/tests/automatic/system_io/read_file_content/CMakeLists.txt
+++ b/tests/automatic/system_io/read_file_content/CMakeLists.txt
@@ -7,7 +7,7 @@ set(SOURCE_FILES read_file_content.cpp)
 ################################
 add_executable(${TARGET_NAME} ${SOURCE_FILES} $<TARGET_OBJECTS:system_io> )
 target_link_libraries(${TARGET_NAME} test_common)
-target_include_directories(${TARGET_NAME} PUBLIC ${HIDRA2_CXX_COMMON_INCLUDE_DIR})
+target_include_directories(${TARGET_NAME} PUBLIC ${CMAKE_SOURCE_DIR}/common/cpp/include)
 set_target_properties(${TARGET_NAME} PROPERTIES LINKER_LANGUAGE CXX)
 
 ################################
diff --git a/tests/automatic/system_io/read_file_content/read_file_content.cpp b/tests/automatic/system_io/read_file_content/read_file_content.cpp
index 065e94328e4523ff40b341ec42de6e3844ad1365..a8dc00ed101e71c29634fd36bfcc265d28836c4f 100644
--- a/tests/automatic/system_io/read_file_content/read_file_content.cpp
+++ b/tests/automatic/system_io/read_file_content/read_file_content.cpp
@@ -1,9 +1,8 @@
 #include <iostream>
-#include <system_wrappers/system_io.h>
+#include "io/io_factory.h"
 
 #include "testing.h"
 
-using hidra2::SystemIO;
 
 int main(int argc, char* argv[]) {
     if (argc != 3) {
@@ -13,7 +12,8 @@ int main(int argc, char* argv[]) {
     std::string expect{argv[2]};
 
     hidra2::Error err;
-    auto io = std::unique_ptr<SystemIO> {new SystemIO};
+    auto io = std::unique_ptr<hidra2::IO> {hidra2::GenerateDefaultIO()};
+
     auto data = io->GetDataFromFile(argv[1], expect.size(), &err);
 
     std::string result;
diff --git a/tests/automatic/system_io/read_folder_content/CMakeLists.txt b/tests/automatic/system_io/read_folder_content/CMakeLists.txt
index bf53584f05643144f8a8c2f3a976428347fa11d5..318db28cd3fbcb9702fd532427321134c6820dbe 100644
--- a/tests/automatic/system_io/read_folder_content/CMakeLists.txt
+++ b/tests/automatic/system_io/read_folder_content/CMakeLists.txt
@@ -7,6 +7,11 @@ set(SOURCE_FILES read_folder_content.cpp)
 ################################
 add_executable(${TARGET_NAME} ${SOURCE_FILES}  $<TARGET_OBJECTS:system_io>)
 target_link_libraries(${TARGET_NAME} test_common)
+
+#Add all necessary common libraries
+GET_PROPERTY(HIDRA2_COMMON_IO_LIBRARIES GLOBAL PROPERTY HIDRA2_COMMON_IO_LIBRARIES)
+target_link_libraries(${TARGET_NAME} ${HIDRA2_COMMON_IO_LIBRARIES})
+
 target_include_directories(${TARGET_NAME} PUBLIC ${HIDRA2_CXX_COMMON_INCLUDE_DIR})
 set_target_properties(${TARGET_NAME} PROPERTIES LINKER_LANGUAGE CXX)
 
diff --git a/tests/automatic/system_io/read_folder_content/read_folder_content.cpp b/tests/automatic/system_io/read_folder_content/read_folder_content.cpp
index 9e6bbbd3ef4f16ad9d7819d9e1b54441650e4299..11ce72c2525f6b48e2a6b31ee613d81723b8c7d3 100644
--- a/tests/automatic/system_io/read_folder_content/read_folder_content.cpp
+++ b/tests/automatic/system_io/read_folder_content/read_folder_content.cpp
@@ -1,9 +1,9 @@
 #include <iostream>
 
-#include "system_wrappers/system_io.h"
+#include "io/io_factory.h"
 #include "testing.h"
 
-using hidra2::SystemIO;
+using hidra2::IO;
 using hidra2::Error;
 
 
@@ -18,7 +18,7 @@ int main(int argc, char* argv[]) {
     std::string expect{argv[2]};
 
     Error err;
-    auto io = std::unique_ptr<SystemIO> {new SystemIO};
+    auto io = std::unique_ptr<IO> {hidra2::GenerateDefaultIO() };
     auto files = io->FilesInFolder(argv[1], &err);
 
     std::string result{};
diff --git a/tests/automatic/system_io/read_string_from_file/read_string_from_file.cpp b/tests/automatic/system_io/read_string_from_file/read_string_from_file.cpp
index 6a41e2e76ec4f39322c9f3118d0f0b620dbd412d..3248c67e5eeb2eeee7648fb06f9d9625dbe05891 100644
--- a/tests/automatic/system_io/read_string_from_file/read_string_from_file.cpp
+++ b/tests/automatic/system_io/read_string_from_file/read_string_from_file.cpp
@@ -1,10 +1,8 @@
 #include <iostream>
-#include <system_wrappers/system_io.h>
+#include "io/io_factory.h"
 
 #include "testing.h"
 
-using hidra2::SystemIO;
-
 int main(int argc, char* argv[]) {
     if (argc != 3) {
         std::cout << "Wrong number of arguments" << std::endl;
@@ -13,7 +11,7 @@ int main(int argc, char* argv[]) {
     std::string expect{argv[2]};
 
     hidra2::Error err;
-    auto io = std::unique_ptr<SystemIO> {new SystemIO};
+    auto io = std::unique_ptr<hidra2::IO> {hidra2::GenerateDefaultIO()};
     auto str = io->ReadFileToString(argv[1], &err);
 
     std::string result;
diff --git a/tests/automatic/system_io/resolve_hostname_to_ip/CMakeLists.txt b/tests/automatic/system_io/resolve_hostname_to_ip/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7bc06ca1db15e1ba4234b02d01538c5132d1474b
--- /dev/null
+++ b/tests/automatic/system_io/resolve_hostname_to_ip/CMakeLists.txt
@@ -0,0 +1,16 @@
+set(TARGET_NAME resolve_hostname_to_ip)
+set(SOURCE_FILES resolve_hostname_to_ip.cpp)
+
+################################
+# Executable and link
+################################
+add_executable(${TARGET_NAME} ${SOURCE_FILES} $<TARGET_OBJECTS:system_io> )
+target_link_libraries(${TARGET_NAME} test_common)
+target_include_directories(${TARGET_NAME} PUBLIC ${HIDRA2_CXX_COMMON_INCLUDE_DIR})
+set_target_properties(${TARGET_NAME} PROPERTIES LINKER_LANGUAGE CXX)
+
+################################
+# Testing
+################################
+
+add_integration_test(${TARGET_NAME} resolve_hostname_to_ip "")
diff --git a/tests/automatic/system_io/resolve_hostname_to_ip/resolve_hostname_to_ip.cpp b/tests/automatic/system_io/resolve_hostname_to_ip/resolve_hostname_to_ip.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a5a3757821a80e3b442df46d7315987fd980b06f
--- /dev/null
+++ b/tests/automatic/system_io/resolve_hostname_to_ip/resolve_hostname_to_ip.cpp
@@ -0,0 +1,38 @@
+#include <iostream>
+#include "io/io_factory.h"
+
+#include "testing.h"
+
+using hidra2::Error;
+using hidra2::ErrorType;
+
+using hidra2::M_AssertEq;
+using hidra2::M_AssertTrue;
+
+
+void Check(const std::string& expected_ip_address, const std::string& hostname) {
+    std::cout << "Checking: " << hostname << std::endl;
+    Error err;
+    auto io = std::unique_ptr<hidra2::IO> {hidra2::GenerateDefaultIO()};
+    std::string ip_address = io->ResolveHostnameToIp(hostname, &err);
+    M_AssertEq(expected_ip_address, ip_address);
+    if(expected_ip_address.empty()) {
+        M_AssertTrue(err != nullptr && hidra2::IOErrorTemplates::kUnableToResolveHostname == err);
+        return;
+    }
+    M_AssertTrue(err == nullptr);
+}
+
+int main(int argc, char* argv[]) {
+    Check("127.0.0.1", "localhost");
+    Check("8.8.8.8", "google-public-dns-a.google.com");
+    Check("8.8.4.4", "google-public-dns-b.google.com");
+    Check("4.2.2.1", "a.resolvers.level3.net");
+    Check("4.2.2.2", "b.resolvers.level3.net");
+    Check("4.2.2.3", "c.resolvers.level3.net");
+    Check("4.2.2.4", "d.resolvers.level3.net");
+
+    Check("", "some-address-that-does-not-exists.ff");
+    Check("", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.ff");
+    return 0;
+}
diff --git a/tests/automatic/system_io/write_data_to_file/CMakeLists.txt b/tests/automatic/system_io/write_data_to_file/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..fd034a4d2385b6b8069962b68ffc0485dd16afaa
--- /dev/null
+++ b/tests/automatic/system_io/write_data_to_file/CMakeLists.txt
@@ -0,0 +1,20 @@
+set(TARGET_NAME write_data_to_file)
+set(SOURCE_FILES write_data_to_file.cpp)
+
+
+################################
+# Executable and link
+################################
+add_executable(${TARGET_NAME} ${SOURCE_FILES} $<TARGET_OBJECTS:system_io> )
+target_link_libraries(${TARGET_NAME} test_common)
+target_include_directories(${TARGET_NAME} PUBLIC ${CMAKE_SOURCE_DIR}/common/cpp/include)
+set_target_properties(${TARGET_NAME} PROPERTIES LINKER_LANGUAGE CXX)
+
+################################
+# Testing
+################################
+add_test_setup_cleanup(${TARGET_NAME})
+add_integration_test(${TARGET_NAME} writeok "test_file ok dummy" nomem)
+add_integration_test(${TARGET_NAME} writetwice "test_file error kFileAlreadyExists:test" nomem)
+add_integration_test(${TARGET_NAME} dirnoaccess "test_noaccess/test_file error Permissiondenied:test_noaccess/test_file" nomem)
+
diff --git a/tests/automatic/system_io/write_data_to_file/cleanup_linux.sh b/tests/automatic/system_io/write_data_to_file/cleanup_linux.sh
new file mode 100644
index 0000000000000000000000000000000000000000..1a50a82324730dc9630f63142d6328926b2ca9f4
--- /dev/null
+++ b/tests/automatic/system_io/write_data_to_file/cleanup_linux.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+rm -f test_file
+rmdir test_noaccess
+
diff --git a/tests/automatic/system_io/write_data_to_file/cleanup_windows.bat b/tests/automatic/system_io/write_data_to_file/cleanup_windows.bat
new file mode 100644
index 0000000000000000000000000000000000000000..256da63ada32b6f56a0273cc6ea378675be066cf
--- /dev/null
+++ b/tests/automatic/system_io/write_data_to_file/cleanup_windows.bat
@@ -0,0 +1,4 @@
+del test_file
+
+icacls test_noaccess /grant:r users:W
+rmdir /S /Q test_noaccess
diff --git a/tests/automatic/system_io/write_data_to_file/setup_linux.sh b/tests/automatic/system_io/write_data_to_file/setup_linux.sh
new file mode 100644
index 0000000000000000000000000000000000000000..63356273ee156761c7bcbcf4a9524d32cf134416
--- /dev/null
+++ b/tests/automatic/system_io/write_data_to_file/setup_linux.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+mkdir test_noaccess
+chmod -rx test_noaccess
+
diff --git a/tests/automatic/system_io/write_data_to_file/setup_windows.bat b/tests/automatic/system_io/write_data_to_file/setup_windows.bat
new file mode 100644
index 0000000000000000000000000000000000000000..bc36d4ed8d9c3ac8e998f8ea7970ce8e1b1bb89d
--- /dev/null
+++ b/tests/automatic/system_io/write_data_to_file/setup_windows.bat
@@ -0,0 +1,5 @@
+mkdir test_noaccess
+icacls test_noaccess /deny users:W
+
+
+
diff --git a/tests/automatic/system_io/write_data_to_file/write_data_to_file.cpp b/tests/automatic/system_io/write_data_to_file/write_data_to_file.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3abfd66d2b90537fcfe8f189918e2a23cdae02b3
--- /dev/null
+++ b/tests/automatic/system_io/write_data_to_file/write_data_to_file.cpp
@@ -0,0 +1,65 @@
+#include <iostream>
+#include "io/io_factory.h"
+
+#include "testing.h"
+
+using hidra2::IO;
+using hidra2::Error;
+using hidra2::FileData;
+
+
+struct Params {
+    std::string fname;
+    std::string result;
+    std::string message;
+    int length;
+};
+
+Params GetParams(int argc, char* argv[]) {
+    if (argc != 4) {
+        std::cout << "Wrong number of arguments" << std::endl;
+        exit(EXIT_FAILURE);
+    }
+    std::string fname{argv[1]};
+    std::string result{argv[2]};
+    std::string message{argv[3]};
+
+    return Params{fname, result, message, 3};
+}
+
+void AssertGoodResult(const std::unique_ptr<IO>& io, const Error& err, const FileData& data,
+                      const Params& params) {
+    if (err) {
+        std::cerr << err << std::endl;
+        exit(EXIT_FAILURE);
+    }
+    Error read_err;
+    auto read_data = io->GetDataFromFile(params.fname, params.length, &read_err);
+    hidra2::M_AssertContains(std::string(read_data.get(), read_data.get() + params.length), "123");
+}
+
+void AssertBadResult(const Error& err, const Params& params) {
+    if (err == nullptr) {
+        std::cerr << "Should be error" << std::endl;
+        exit(EXIT_FAILURE);
+    }
+    hidra2::M_AssertContains(err->Explain(), params.message);
+}
+
+
+int main(int argc, char* argv[]) {
+    auto params = GetParams(argc, argv);
+
+    auto io = std::unique_ptr<hidra2::IO> {hidra2::GenerateDefaultIO()};
+    FileData data{new uint8_t[params.length]{'1', '2', '3'}};
+
+    auto err = io->WriteDataToFile(params.fname, data, params.length);
+
+    if (params.result == "ok") {
+        AssertGoodResult(io, err, data, params);
+    } else {
+        AssertBadResult(err, params);
+    }
+
+    return 0;
+}
diff --git a/tests/automatic/worker/connect_multithread/CMakeLists.txt b/tests/automatic/worker/connect_multithread/CMakeLists.txt
index 31364d77e74b1b833bc6d06d63105fbdf967f9f6..abe83367dc6b2796d7ca4d734b6ed4d37b8ed167 100644
--- a/tests/automatic/worker/connect_multithread/CMakeLists.txt
+++ b/tests/automatic/worker/connect_multithread/CMakeLists.txt
@@ -6,7 +6,7 @@ set(SOURCE_FILES content_multithread.cpp)
 # Executable and link
 ################################
 add_executable(${TARGET_NAME} ${SOURCE_FILES})
-target_link_libraries(${TARGET_NAME} test_common hidra2-worker ${CMAKE_THREAD_LIBS_INIT})
+target_link_libraries(${TARGET_NAME} test_common hidra2-worker ${HIDRA2_COMMON_IO_LIBRARIES})
 set_target_properties(${TARGET_NAME} PROPERTIES LINKER_LANGUAGE CXX)
 if (CMAKE_COMPILER_IS_GNUCXX)
     set_target_properties(${TARGET_NAME} PROPERTIES LINK_FLAGS_DEBUG "--coverage")
diff --git a/tests/automatic/worker/curl_http_client_get/curl_httpclient_get.cpp b/tests/automatic/worker/curl_http_client_get/curl_httpclient_get.cpp
index 057c474f1445e4b02a95e6480eafe5b39d9ae745..478839271d364ce2bcfa98cc00de5ac4f602707d 100644
--- a/tests/automatic/worker/curl_http_client_get/curl_httpclient_get.cpp
+++ b/tests/automatic/worker/curl_http_client_get/curl_httpclient_get.cpp
@@ -34,15 +34,15 @@ int main(int argc, char* argv[]) {
     auto server_broker = static_cast<hidra2::ServerDataBroker*>(broker.get());
 
     hidra2::HttpCode code;
-    auto responce = server_broker->httpclient__->Get(args.uri, &code, &err);
+    auto response = server_broker->httpclient__->Get(args.uri, &code, &err);
 
     if (err != nullptr) {
         M_AssertEq("clienterror", args.answer);
-        M_AssertContains(responce, "Could");
+        M_AssertContains(response, "Could");
         return 0;
     }
 
-    M_AssertContains(responce, args.answer);
+    M_AssertContains(response, args.answer);
     M_AssertEq(static_cast<int>(code), args.code);
 
     return 0;
diff --git a/tests/automatic/worker/next_multithread_folder/CMakeLists.txt b/tests/automatic/worker/next_multithread_folder/CMakeLists.txt
index 685e69ffc1d84c130f0acf98f264d7096bd6c15d..eed3cc9b92840d9f2fe0aebda644df863acb553a 100644
--- a/tests/automatic/worker/next_multithread_folder/CMakeLists.txt
+++ b/tests/automatic/worker/next_multithread_folder/CMakeLists.txt
@@ -6,7 +6,17 @@ set(SOURCE_FILES next_multithread_folder.cpp)
 # Executable and link
 ################################
 add_executable(${TARGET_NAME} ${SOURCE_FILES})
-target_link_libraries(${TARGET_NAME} test_common hidra2-worker  ${CMAKE_THREAD_LIBS_INIT})
+
+#Add all necessary common libraries
+GET_PROPERTY(HIDRA2_COMMON_IO_LIBRARIES GLOBAL PROPERTY HIDRA2_COMMON_IO_LIBRARIES)
+target_link_libraries(${TARGET_NAME} ${HIDRA2_COMMON_IO_LIBRARIES})
+
+target_link_libraries(${TARGET_NAME} test_common hidra2-worker)
+set_target_properties(${TARGET_NAME} PROPERTIES LINKER_LANGUAGE CXX)
+if (CMAKE_COMPILER_IS_GNUCXX)
+    set_target_properties(${TARGET_NAME} PROPERTIES LINK_FLAGS_DEBUG "--coverage")
+endif()
+
 
 ################################
 # Testing
diff --git a/worker/api/cpp/src/curl_http_client.cpp b/worker/api/cpp/src/curl_http_client.cpp
index 4cec61f6875159372afdc316b90d018baf8da52f..364b87cd1975a90de5ec53cc3eefaeb8e126265c 100644
--- a/worker/api/cpp/src/curl_http_client.cpp
+++ b/worker/api/cpp/src/curl_http_client.cpp
@@ -35,7 +35,7 @@ void SetCurlOptions(CURL* curl, const std::string& uri, char* errbuf, std::strin
 
 }
 
-HttpCode GetResponceCode(CURL* curl) {
+HttpCode GetResponseCode(CURL* curl) {
     long http_code = 0;
     curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &http_code);
     return static_cast<HttpCode>(http_code);
@@ -49,10 +49,10 @@ std::string GetCurlError(CURL* curl, CURLcode res, const char* errbuf) {
     }
 }
 
-Error ProcessCurlResponce(CURL* curl, CURLcode res, const char* errbuf,
-                          std::string* buffer, HttpCode* responce_code) {
+Error ProcessCurlResponse(CURL* curl, CURLcode res, const char* errbuf,
+                          std::string* buffer, HttpCode* response_code) {
     if(res == CURLE_OK) {
-        *responce_code = GetResponceCode(curl);
+        *response_code = GetResponseCode(curl);
         return nullptr;
     } else {
         *buffer = GetCurlError(curl, res, errbuf);
@@ -60,7 +60,7 @@ Error ProcessCurlResponce(CURL* curl, CURLcode res, const char* errbuf,
     }
 }
 
-std::string CurlHttpClient::Get(const std::string& uri, HttpCode* responce_code, Error* err) const noexcept {
+std::string CurlHttpClient::Get(const std::string& uri, HttpCode* response_code, Error* err) const noexcept {
     std::lock_guard<std::mutex> lock{mutex_};
 
     std::string buffer;
@@ -69,7 +69,7 @@ std::string CurlHttpClient::Get(const std::string& uri, HttpCode* responce_code,
 
     auto res = curl_easy_perform(curl_);
 
-    *err = ProcessCurlResponce(curl_, res, errbuf, &buffer, responce_code);
+    *err = ProcessCurlResponse(curl_, res, errbuf, &buffer, response_code);
 
     return buffer;
 }
diff --git a/worker/api/cpp/src/curl_http_client.h b/worker/api/cpp/src/curl_http_client.h
index 578c033370a26f36f99a94bd665b3147fd4d342a..135a6cd5c5b38af9e3d54421538a2197ee9b0889 100644
--- a/worker/api/cpp/src/curl_http_client.h
+++ b/worker/api/cpp/src/curl_http_client.h
@@ -12,7 +12,7 @@ namespace hidra2 {
 class CurlHttpClient final : public HttpClient {
   public:
     CurlHttpClient();
-    std::string Get(const std::string& uri, HttpCode* responce_code, Error* err) const noexcept override;
+    std::string Get(const std::string& uri, HttpCode* response_code, Error* err) const noexcept override;
     virtual ~CurlHttpClient();
   private:
     mutable std::mutex mutex_;
diff --git a/worker/api/cpp/src/folder_data_broker.cpp b/worker/api/cpp/src/folder_data_broker.cpp
index f312536460ac664c815cc71200498dfa6f311b67..f15b3d6a260a80c8c14e3de635046c1654af077a 100644
--- a/worker/api/cpp/src/folder_data_broker.cpp
+++ b/worker/api/cpp/src/folder_data_broker.cpp
@@ -1,12 +1,12 @@
 #include "folder_data_broker.h"
 
-#include "system_wrappers/system_io.h"
+#include "io/io_factory.h"
 
 namespace hidra2 {
 
 FolderDataBroker::FolderDataBroker(const std::string& source_name) :
-    io__{new hidra2::SystemIO}, base_path_{source_name}, is_connected_{false},
-current_file_{ -1} {
+    io__{GenerateDefaultIO()}, base_path_{source_name}, is_connected_{false},
+    current_file_{ -1} {
 }
 
 Error FolderDataBroker::Connect() {
@@ -37,7 +37,7 @@ Error FolderDataBroker::CanGetData(FileInfo* info, FileData* data, int nfile) co
     }
 
     if (nfile >= (int) filelist_.size()) {
-        return Error{TextErrorWithType(WorkerErrorMessage::kNoData, ErrorType::kEOF)};
+        return Error{TextErrorWithType(WorkerErrorMessage::kNoData, ErrorType::kEndOfFile)};
     }
     return nullptr;
 }
@@ -67,4 +67,4 @@ Error FolderDataBroker::GetNext(FileInfo* info, FileData* data) {
 }
 
 
-}
\ No newline at end of file
+}
diff --git a/worker/api/cpp/src/folder_data_broker.h b/worker/api/cpp/src/folder_data_broker.h
index 4ffe1b21177d770253bda50aae9c06567f5ad93b..f388e5b1fd726b34eae9035670b035ce1695af39 100644
--- a/worker/api/cpp/src/folder_data_broker.h
+++ b/worker/api/cpp/src/folder_data_broker.h
@@ -6,7 +6,7 @@
 #include <string>
 #include <mutex>
 
-#include "system_wrappers/io.h"
+#include "io/io.h"
 
 namespace hidra2 {
 
diff --git a/worker/api/cpp/src/http_client.cpp b/worker/api/cpp/src/http_client.cpp
index acfec717cbe1546e7f696c9a441c087933e4275c..d5c86c6c07343e163714d36a2b22053138bec407 100644
--- a/worker/api/cpp/src/http_client.cpp
+++ b/worker/api/cpp/src/http_client.cpp
@@ -15,7 +15,7 @@ Error HttpCodeToWorkerError(const HttpCode& code) {
         break;
     case HttpCode::NoContent:
         message = WorkerErrorMessage::kNoData;
-        return TextErrorWithType(message, ErrorType::kEOF);
+        return TextErrorWithType(message, ErrorType::kEndOfFile);
     case HttpCode::NotFound:
         message = WorkerErrorMessage::kSourceNotFound;
         break;
diff --git a/worker/api/cpp/src/http_client.h b/worker/api/cpp/src/http_client.h
index 725af46011eae69bf660d647cb1a601e511e9a7f..31b838a62924f70fe83aecd5e70b4654421671aa 100644
--- a/worker/api/cpp/src/http_client.h
+++ b/worker/api/cpp/src/http_client.h
@@ -9,7 +9,7 @@ enum class HttpCode;
 
 class HttpClient {
   public:
-    virtual std::string Get(const std::string& uri, HttpCode* responce_code, Error* err) const noexcept = 0;
+    virtual std::string Get(const std::string& uri, HttpCode* response_code, Error* err) const noexcept = 0;
     virtual ~HttpClient() = default;
 
 };
diff --git a/worker/api/cpp/src/server_data_broker.cpp b/worker/api/cpp/src/server_data_broker.cpp
index 4712df342d35e765852035bbe7113eb8041fdce8..0298c82db4d538a0c0202ff7efb82fa10b16752a 100644
--- a/worker/api/cpp/src/server_data_broker.cpp
+++ b/worker/api/cpp/src/server_data_broker.cpp
@@ -1,12 +1,12 @@
 #include "server_data_broker.h"
-#include "system_wrappers/system_io.h"
+#include "io/io_factory.h"
 #include "curl_http_client.h"
 
 namespace hidra2 {
 
 ServerDataBroker::ServerDataBroker(const std::string& server_uri,
                                    const std::string& source_name):
-    io__{new hidra2::SystemIO}, httpclient__{new hidra2::CurlHttpClient},
+    io__{GenerateDefaultIO()}, httpclient__{new CurlHttpClient},
 server_uri_{server_uri}, source_name_{source_name} {
 }
 
@@ -18,7 +18,7 @@ Error ServerDataBroker::GetFileInfoFromServer(FileInfo* info, const std::string&
     std::string full_uri = server_uri_ + "/database/" + source_name_ + "/" + operation;
     Error err;
     HttpCode code;
-    auto responce = httpclient__->Get(full_uri, &code, &err);
+    auto response = httpclient__->Get(full_uri, &code, &err);
 
     if (err != nullptr) {
         return err;
@@ -26,11 +26,11 @@ Error ServerDataBroker::GetFileInfoFromServer(FileInfo* info, const std::string&
 
     err = HttpCodeToWorkerError(code);
     if (err != nullptr) {
-        err->Append(responce);
+        err->Append(response);
         return err;
     }
 
-    if (!info->SetFromJson(responce)) {
+    if (!info->SetFromJson(response)) {
         return TextError(WorkerErrorMessage::kErrorReadingSource);
     }
     return nullptr;
@@ -55,4 +55,4 @@ Error ServerDataBroker::GetNext(FileInfo* info, FileData* data) {
     return error;
 }
 
-}
\ No newline at end of file
+}
diff --git a/worker/api/cpp/src/server_data_broker.h b/worker/api/cpp/src/server_data_broker.h
index d77fff8bfddc4ea7e204e5b1a5c823a774967230..2081261b832c9884e8c762983f58c43adf91579e 100644
--- a/worker/api/cpp/src/server_data_broker.h
+++ b/worker/api/cpp/src/server_data_broker.h
@@ -2,7 +2,7 @@
 #define HIDRA2_SERVER_DATA_BROKER_H
 
 #include "worker/data_broker.h"
-#include "system_wrappers/io.h"
+#include "io/io.h"
 #include "http_client.h"
 
 
diff --git a/worker/api/cpp/unittests/test_folder_broker.cpp b/worker/api/cpp/unittests/test_folder_broker.cpp
index 2190b9d27a89750d32eca1d10d1cb221b602a162..796183e246a718452536652f071b8507e9a7ee06 100644
--- a/worker/api/cpp/unittests/test_folder_broker.cpp
+++ b/worker/api/cpp/unittests/test_folder_broker.cpp
@@ -1,9 +1,10 @@
 #include <gmock/gmock.h>
+#include <unittests/MockIO.h>
 #include "gtest/gtest.h"
 
 #include "worker/data_broker.h"
-#include "system_wrappers/io.h"
-#include "system_wrappers/system_io.h"
+#include "io/io.h"
+#include "../../../../common/cpp/src/system_io/system_io.h"
 #include "../src/folder_data_broker.h"
 
 using hidra2::DataBrokerFactory;
@@ -33,39 +34,13 @@ TEST(FolderDataBroker, SetCorrectIO) {
     delete data_broker;
 }
 
-
-
-class FakeIO: public IO {
+class FakeIO: public hidra2::MockIO {
   public:
 
-    virtual std::string ReadFileToString(const std::string& fname, Error* err)const noexcept  override {
+    virtual std::string ReadFileToString(const std::string& fname, Error* err) const noexcept override {
         return "OK";
     }
 
-
-    virtual uint8_t* GetDataFromFileProxy(const std::string& fname, uint64_t fsize, SimpleError** err) const {
-        *err = nullptr;
-        return nullptr;
-    };
-
-    FileData GetDataFromFile(const std::string& fname, uint64_t fsize, Error* err) const noexcept override {
-        SimpleError* error;
-        auto data = GetDataFromFileProxy(fname, fsize, &error);
-        err->reset(error);
-        return FileData(data);
-    };
-
-    int open(const char* __file, int __oflag) const noexcept override {
-        return 0;
-    };
-
-    int close(int __fd)const noexcept override {
-        return 0;
-    };
-
-    uint64_t Read(int fd, uint8_t* array, uint64_t fsize, Error* err) const noexcept override {
-        return 0;
-    };
     FileInfos FilesInFolder(const std::string& folder, Error* err) const override {
         *err = nullptr;
         FileInfos file_infos;
@@ -84,7 +59,7 @@ class FakeIO: public IO {
 class IOFolderNotFound: public FakeIO {
   public:
     FileInfos FilesInFolder(const std::string& folder, Error* err) const override {
-        *err = hidra2::TextError(hidra2::IOErrors::kFileNotFound);
+        *err = hidra2::IOErrorTemplates::kFileNotFound.Generate();
         return {};
     }
 };
@@ -92,7 +67,7 @@ class IOFolderNotFound: public FakeIO {
 class IOFolderUnknownError: public FakeIO {
   public:
     FileInfos FilesInFolder(const std::string& folder, Error* err) const override {
-        *err = hidra2::TextError(hidra2::IOErrors::kUnknownError);
+        *err  = hidra2::IOErrorTemplates::kUnknownIOError.Generate();
         return {};
     }
 };
@@ -108,7 +83,7 @@ class IOEmptyFolder: public FakeIO {
 class IOCannotOpenFile: public FakeIO {
   public:
     FileData GetDataFromFile(const std::string& fname, uint64_t fsize, Error* err) const noexcept override {
-        *err = hidra2::TextError(hidra2::IOErrors::kPermissionDenied);
+        *err = hidra2::IOErrorTemplates::kPermissionDenied.Generate();
         return {};
     };
 };
@@ -146,7 +121,7 @@ TEST_F(FolderDataBrokerTests, CannotConnectWhenNoFolder) {
 
     auto return_code = data_broker->Connect();
 
-    ASSERT_THAT(return_code->Explain(), Eq(hidra2::IOErrors::kFileNotFound));
+    ASSERT_THAT(return_code->Explain(), Eq(hidra2::IOErrorTemplates::kFileNotFound.Generate()->Explain()));
 }
 
 TEST_F(FolderDataBrokerTests, ConnectReturnsUnknownIOError) {
@@ -154,7 +129,7 @@ TEST_F(FolderDataBrokerTests, ConnectReturnsUnknownIOError) {
 
     auto return_code = data_broker->Connect();
 
-    ASSERT_THAT(return_code->Explain(), Eq(hidra2::IOErrors::kUnknownError));
+    ASSERT_THAT(return_code->Explain(), Eq(hidra2::IOErrorTemplates::kUnknownIOError.Generate()->Explain()));
 }
 
 TEST_F(FolderDataBrokerTests, GetNextWithoutConnectReturnsError) {
@@ -200,12 +175,11 @@ TEST_F(FolderDataBrokerTests, GetNextFromEmptyFolderReturnsError) {
     FileInfo fi;
 
     auto err = data_broker->GetNext(&fi, nullptr);
-    ASSERT_THAT(err->GetErrorType(), Eq(hidra2::ErrorType::kEOF));
+    ASSERT_TRUE(hidra2::ErrorTemplates::kEndOfFile == err);
 
     ASSERT_THAT(err->Explain(), Eq(hidra2::WorkerErrorMessage::kNoData));
 }
 
-
 TEST_F(FolderDataBrokerTests, GetNextReturnsErrorWhenFilePermissionsDenied) {
     data_broker->io__ = std::unique_ptr<IO> {new IOCannotOpenFile()};
     data_broker->Connect();
@@ -213,16 +187,13 @@ TEST_F(FolderDataBrokerTests, GetNextReturnsErrorWhenFilePermissionsDenied) {
     FileData data;
 
     auto err = data_broker->GetNext(&fi, &data);
-    ASSERT_THAT(err->Explain(), Eq(hidra2::IOErrors::kPermissionDenied));
+    ASSERT_THAT(err->Explain(), Eq(hidra2::IOErrorTemplates::kPermissionDenied.Generate()->Explain()));
 }
 
 
 class OpenFileMock : public FakeIO {
-  public:
-    MOCK_CONST_METHOD3(GetDataFromFileProxy, uint8_t* (const std::string&, uint64_t, SimpleError**));
 };
 
-
 class GetDataFromFileTests : public Test {
   public:
     std::unique_ptr<FolderDataBroker> data_broker;
@@ -240,16 +211,14 @@ class GetDataFromFileTests : public Test {
 };
 
 TEST_F(GetDataFromFileTests, GetNextCallsGetDataFileWithFileName) {
-    EXPECT_CALL(mock, GetDataFromFileProxy("/path/to/file/1", _, _)).
+    EXPECT_CALL(mock, GetDataFromFile_t("/path/to/file/1", _, _)).
     WillOnce(DoAll(testing::SetArgPointee<2>(static_cast<SimpleError*>(nullptr)), testing::Return(nullptr)));
 
     data_broker->GetNext(&fi, &data);
 }
 
-
-
 TEST_F(GetDataFromFileTests, GetNextReturnsDataAndInfo) {
-    EXPECT_CALL(mock, GetDataFromFileProxy(_, _, _)).
+    EXPECT_CALL(mock, GetDataFromFile_t(_, _, _)).
     WillOnce(DoAll(testing::SetArgPointee<2>(nullptr), testing::Return(new uint8_t[1] {'1'})));
 
     data_broker->GetNext(&fi, &data);
@@ -259,26 +228,24 @@ TEST_F(GetDataFromFileTests, GetNextReturnsDataAndInfo) {
 
 }
 
-
-
 TEST_F(GetDataFromFileTests, GetNextReturnsErrorWhenCannotReadData) {
-    EXPECT_CALL(mock, GetDataFromFileProxy(_, _, _)).
-    WillOnce(DoAll(testing::SetArgPointee<2>(new SimpleError(hidra2::IOErrors::kReadError)), testing::Return(nullptr)));
+    EXPECT_CALL(mock, GetDataFromFile_t(_, _, _)).
+    WillOnce(DoAll(testing::SetArgPointee<2>(hidra2::IOErrorTemplates::kReadError.Generate().release()),
+                   testing::Return(nullptr)));
 
     auto err = data_broker->GetNext(&fi, &data);
 
-    ASSERT_THAT(err->Explain(), Eq(hidra2::IOErrors::kReadError));
+    ASSERT_THAT(err->Explain(), Eq(hidra2::IOErrorTemplates::kReadError.Generate()->Explain()));
 }
 
-
 TEST_F(GetDataFromFileTests, GetNextReturnsErrorWhenCannotAllocateData) {
-    EXPECT_CALL(mock, GetDataFromFileProxy(_, _, _)).
-    WillOnce(DoAll(testing::SetArgPointee<2>(new SimpleError(hidra2::IOErrors::kMemoryAllocationError)),
+    EXPECT_CALL(mock, GetDataFromFile_t(_, _, _)).
+    WillOnce(DoAll(testing::SetArgPointee<2>(hidra2::ErrorTemplates::kMemoryAllocationError.Generate().release()),
                    testing::Return(nullptr)));
 
     auto err = data_broker->GetNext(&fi, &data);
 
-    ASSERT_THAT(err->Explain(), Eq(hidra2::IOErrors::kMemoryAllocationError));
+    ASSERT_THAT(err->Explain(), Eq(hidra2::ErrorTemplates::kMemoryAllocationError.Generate()->Explain()));
 }
 
 
diff --git a/worker/api/cpp/unittests/test_server_broker.cpp b/worker/api/cpp/unittests/test_server_broker.cpp
index 9362bc61f6419b22f79e00a6cf3b6a969e661989..48296c46fdb53baa0cdca421aa692b6e22c34de8 100644
--- a/worker/api/cpp/unittests/test_server_broker.cpp
+++ b/worker/api/cpp/unittests/test_server_broker.cpp
@@ -2,8 +2,8 @@
 #include "gtest/gtest.h"
 
 #include "worker/data_broker.h"
-#include "system_wrappers/io.h"
-#include "system_wrappers/system_io.h"
+#include "io/io.h"
+#include "../../../../common/cpp/src/system_io/system_io.h"
 #include "../src/server_data_broker.h"
 #include "../src/curl_http_client.h"
 #include "unittests/MockIO.h"
@@ -32,7 +32,7 @@ using ::testing::Mock;
 using ::testing::NiceMock;
 using ::testing::Return;
 using ::testing::SetArgPointee;
-
+using ::testing::SetArgReferee;
 
 namespace {
 
@@ -63,11 +63,11 @@ class ServerDataBrokerTests : public Test {
         data_broker->io__.release();
         data_broker->httpclient__.release();
     }
-    void MockGet(const std::string& responce) {
+    void MockGet(const std::string& response) {
         EXPECT_CALL(mock_http_client, Get_t(_, _, _)).WillOnce(DoAll(
                     SetArgPointee<1>(HttpCode::OK),
                     SetArgPointee<2>(nullptr),
-                    Return(responce)
+                    Return(response)
                 ));
     }
 
@@ -114,7 +114,7 @@ TEST_F(ServerDataBrokerTests, GetNextReturnsEOFFromHttpClient) {
     auto err = data_broker->GetNext(&info, nullptr);
 
     ASSERT_THAT(err->Explain(), HasSubstr(hidra2::WorkerErrorMessage::kNoData));
-    ASSERT_THAT(err->GetErrorType(), hidra2::ErrorType::kEOF);
+    ASSERT_THAT(err->GetErrorType(), hidra2::ErrorType::kEndOfFile);
 }
 
 
@@ -145,7 +145,7 @@ TEST_F(ServerDataBrokerTests, GetNextReturnsFileInfo) {
 
 
 TEST_F(ServerDataBrokerTests, GetNextReturnsParseError) {
-    MockGet("error_responce");
+    MockGet("error_response");
     auto err = data_broker->GetNext(&info, nullptr);
 
     ASSERT_THAT(err->Explain(), Eq(hidra2::WorkerErrorMessage::kErrorReadingSource));
@@ -153,13 +153,12 @@ TEST_F(ServerDataBrokerTests, GetNextReturnsParseError) {
 
 
 TEST_F(ServerDataBrokerTests, GetNextReturnsIfNoDtataNeeded) {
-    MockGet("error_responce");
+    MockGet("error_response");
     EXPECT_CALL( mock_io, GetDataFromFile_t(_, _, _)).Times(0);
 
     data_broker->GetNext(&info, nullptr);
 }
 
-
 TEST_F(ServerDataBrokerTests, GetNextCallsReadFromFile) {
     auto to_send = CreateFI();
     auto json = to_send.Json();
@@ -167,7 +166,7 @@ TEST_F(ServerDataBrokerTests, GetNextCallsReadFromFile) {
     MockGet(json);
 
     EXPECT_CALL(mock_io, GetDataFromFile_t("name", 100, _)).
-    WillOnce(DoAll(SetArgPointee<2>(new SimpleError{hidra2::IOErrors::kReadError}), testing::Return(nullptr)));
+    WillOnce(DoAll(SetArgPointee<2>(new hidra2::SimpleError{"s"}), testing::Return(nullptr)));
 
     FileData data;
     data_broker->GetNext(&info, &data);
diff --git a/worker/tools/folder_to_db/src/folder_db_importer.cpp b/worker/tools/folder_to_db/src/folder_db_importer.cpp
index 916f06c10bfbc6cf0061a1361de414bb48523b80..1bc002c7e1dda0e3502b97527fb314e7795cc531 100644
--- a/worker/tools/folder_to_db/src/folder_db_importer.cpp
+++ b/worker/tools/folder_to_db/src/folder_db_importer.cpp
@@ -3,7 +3,7 @@
 #include <future>
 #include <algorithm>
 
-#include "system_wrappers/system_io.h"
+#include "io/io_factory.h"
 #include "database/database.h"
 
 
@@ -12,7 +12,7 @@ namespace hidra2 {
 using std::chrono::high_resolution_clock;
 
 FolderToDbImporter::FolderToDbImporter() :
-    io__{new hidra2::SystemIO}, db_factory__{new hidra2::DatabaseFactory} {
+    io__{GenerateDefaultIO()}, db_factory__{new hidra2::DatabaseFactory} {
 }
 
 Error FolderToDbImporter::ConnectToDb(const std::unique_ptr<hidra2::Database>& db) const {
diff --git a/worker/tools/folder_to_db/src/folder_db_importer.h b/worker/tools/folder_to_db/src/folder_db_importer.h
index aecadd203618af74b16bb46ed6aa88cc110750b7..619d8d2646e6aca866b4553c67198c3f20887e99 100644
--- a/worker/tools/folder_to_db/src/folder_db_importer.h
+++ b/worker/tools/folder_to_db/src/folder_db_importer.h
@@ -6,7 +6,7 @@
 #include <future>
 
 
-#include "system_wrappers/io.h"
+#include "io/io.h"
 #include "database/database.h"
 #include "common/error.h"
 namespace hidra2 {
diff --git a/worker/tools/folder_to_db/unittests/test_folder_to_db.cpp b/worker/tools/folder_to_db/unittests/test_folder_to_db.cpp
index 196ff2a7c223876182931f85a48b9ee89e292390..cd9f6991b7b0284efe3761217db56baebeeb43fe 100644
--- a/worker/tools/folder_to_db/unittests/test_folder_to_db.cpp
+++ b/worker/tools/folder_to_db/unittests/test_folder_to_db.cpp
@@ -2,8 +2,8 @@
 #include "gtest/gtest.h"
 #include <thread>
 
-#include "system_wrappers/io.h"
-#include "system_wrappers/system_io.h"
+#include "io/io.h"
+#include "../../../../common/cpp/src/system_io/system_io.h"
 
 
 #include "database/database.h"