diff --git a/.gitignore b/.gitignore
index c5ca081f079ab83aff2b6a136325d1ea45df6231..108f49f167c83fdde2b86280e21114ee2b9278a2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,5 +4,4 @@ build
 **/config.cpp
 **/config.h
 _CPack_Packages
-.vscode
 .env
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 4ac5f2677d2092ac3d1d09767fff016ce45a2455..c7d969ce20ae4cef7b5bd7eda8783a0b49dc9509 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -64,6 +64,7 @@
         "thread": "cpp",
         "typeinfo": "cpp",
         "valarray": "cpp",
-        "variant": "cpp"
+        "variant": "cpp",
+        "any": "cpp"
     }
 }
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 886295cf67665f6d06be520923d8a68ca01381e7..f8daf9f6956d648e5ebc926452687cda8be6f981 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -111,7 +111,7 @@ if (WIN32) # TODO(nick) Should do based upon compiler (VS)
 else()
 	add_definitions(-DUNIX)
 	# -fdiagnostics-color
-	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=always -std=c++17 -fPIC -march=haswell -mavx2 -mfpmath=sse -Wall -Werror=unused-result -Werror=return-type")
+	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=always -std=c++17 -fPIC -march=haswell -mavx2 -mfpmath=sse -Wall -Werror")
 	set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -pg")
 	set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
 	set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -O3")
diff --git a/include/ftl/exception.hpp b/include/ftl/exception.hpp
index 8c140ef86e9182208154d563abc87ee8bc77edd2..ad002ea3a3a2be934cb67193933aca677e472b6e 100644
--- a/include/ftl/exception.hpp
+++ b/include/ftl/exception.hpp
@@ -7,70 +7,68 @@
 #pragma once
 
 #include <sstream>
+#include <string>
 
 namespace ftl {
 class Formatter {
-	public:
-	Formatter() {}
-	~Formatter() {}
-
-	template <typename Type>
-	inline Formatter & operator << (const Type & value)
-	{
-		stream_ << value;
-		return *this;
-	}
-
-	inline std::string str() const         { return stream_.str(); }
-	inline operator std::string () const   { return stream_.str(); }
-
-	enum ConvertToString
-	{
-		to_str
-	};
-	inline std::string operator >> (ConvertToString) { return stream_.str(); }
-
-private:
-	std::stringstream stream_;
-
-	Formatter(const Formatter &);
-	Formatter & operator = (Formatter &);
+ public:
+    Formatter() {}
+    ~Formatter() {}
+
+    template <typename Type>
+    inline Formatter & operator << (const Type & value) {
+        stream_ << value;
+        return *this;
+    }
+
+    inline std::string str() const         { return stream_.str(); }
+    inline operator std::string () const   { return stream_.str(); }
+
+    enum ConvertToString {
+        to_str
+    };
+    inline std::string operator >> (ConvertToString) { return stream_.str(); }
+
+ private:
+    std::stringstream stream_;
+
+    Formatter(const Formatter &);
+    Formatter & operator = (Formatter &);
 };
 
 /**
  * Main FTL internal exception class. Use via Macro below.
  */
-class exception : public std::exception
-{
-	public:
-	explicit exception(const char *msg);
-	explicit exception(const Formatter &msg);
-	~exception();
+class exception : public std::exception {
+ public:
+    explicit exception(const char *msg);
+    explicit exception(const Formatter &msg);
+    ~exception();
 
-	const char* what() const throw () {
-		processed_ = true;
-		return msg_.c_str();
-	}
+    const char* what() const throw() {
+        processed_ = true;
+        return msg_.c_str();
+    }
 
-	std::string trace() const throw () {
-		return decode_backtrace();
-	}
+    std::string trace() const throw() {
+        return decode_backtrace();
+    }
 
-	void ignore() const { processed_ = true; }
+    void ignore() const { processed_ = true; }
 
-	private:
-	std::string decode_backtrace() const;
+ private:
+    std::string decode_backtrace() const;
 
-	std::string msg_;
-	mutable bool processed_;
+    std::string msg_;
+    mutable bool processed_;
 
 #ifdef __GNUC__
-	static const int TRACE_SIZE_MAX_ = 16;
-	void* trace_[TRACE_SIZE_MAX_];
-	int trace_size_;
+    static const int TRACE_SIZE_MAX_ = 16;
+    void* trace_[TRACE_SIZE_MAX_];
+    int trace_size_;
 #endif
 };
 
-}
+}  // namespace ftl
 
 #define FTL_Error(A) (ftl::exception(ftl::Formatter() << A << " [" << __FILE__ << ":" << __LINE__ << "]"))
diff --git a/include/ftl/handle.hpp b/include/ftl/handle.hpp
index c30bae558a9f413d6ddd3421b9b5c30ce582da78..0744c914b6d15092585cdb5fdda1ef0f37bc44d7 100644
--- a/include/ftl/handle.hpp
+++ b/include/ftl/handle.hpp
@@ -6,24 +6,25 @@
 
 #pragma once
 
-#include <ftl/threads.hpp>
-#include <ftl/exception.hpp>
 #include <functional>
 #include <unordered_map>
+#include <utility>
+#include <ftl/threads.hpp>
+#include <ftl/exception.hpp>
 
 namespace ftl {
 
 struct Handle;
 struct BaseHandler {
-	virtual void remove(const Handle &)=0;
+    virtual void remove(const Handle &) = 0;
 
-	virtual void removeUnsafe(const Handle &)=0;
+    virtual void removeUnsafe(const Handle &) = 0;
 
-	inline Handle make_handle(BaseHandler*, int);
+    inline Handle make_handle(BaseHandler*, int);
 
-	protected:
-	std::mutex mutex_;
-	int id_=0;
+ protected:
+    std::mutex mutex_;
+    int id_ = 0;
 };
 
 /**
@@ -31,48 +32,58 @@ struct BaseHandler {
  * removed safely whenever the `Handle` instance is destroyed.
  */
 struct [[nodiscard]] Handle {
-	friend struct BaseHandler;
-
-	/**
-	 * Cancel the callback and invalidate the handle.
-	 */
-	inline void cancel() { if (handler_) handler_->remove(*this); handler_ = nullptr; }
-
-	inline void innerCancel() { if (handler_) handler_->removeUnsafe(*this); handler_ = nullptr; }
-
-	inline int id() const { return id_; }
-
-	Handle() : handler_(nullptr), id_(0) {}
-
-	Handle(const Handle &)=delete;
-	Handle &operator=(const Handle &)=delete;
-
-	inline Handle(Handle &&h) : handler_(nullptr) {
-		if (handler_) handler_->remove(*this);
-		handler_ = h.handler_;
-		h.handler_ = nullptr;
-		id_ = h.id_;
-	}
-
-	inline Handle &operator=(Handle &&h) {
-		if (handler_) handler_->remove(*this);
-		handler_ = h.handler_;
-		h.handler_ = nullptr;
-		id_ = h.id_;
-		return *this;
-	}
-
-	inline ~Handle() {
-		if (handler_) {
-			handler_->remove(*this);
-		}
-	}
-
-	private:
-	BaseHandler *handler_;
-	int id_;
-
-	Handle(BaseHandler *h, int id) : handler_(h), id_(id) {}
+    friend struct BaseHandler;
+
+    /**
+     * Cancel the callback and invalidate the handle.
+     */
+    inline void cancel() {
+        if (handler_) {
+            handler_->remove(*this);
+        }
+        handler_ = nullptr;
+    }
+
+    inline void innerCancel() {
+        if (handler_) {
+            handler_->removeUnsafe(*this);
+        }
+        handler_ = nullptr;
+    }
+
+    inline int id() const { return id_; }
+
+    Handle() : handler_(nullptr), id_(0) {}
+
+    Handle(const Handle &) = delete;
+    Handle &operator=(const Handle &) = delete;
+
+    inline Handle(Handle &&h) : handler_(nullptr) {
+        if (handler_) handler_->remove(*this);
+        handler_ = h.handler_;
+        h.handler_ = nullptr;
+        id_ = h.id_;
+    }
+
+    inline Handle &operator=(Handle &&h) {
+        if (handler_) handler_->remove(*this);
+        handler_ = h.handler_;
+        h.handler_ = nullptr;
+        id_ = h.id_;
+        return *this;
+    }
+
+    inline ~Handle() {
+        if (handler_) {
+            handler_->remove(*this);
+        }
+    }
+
+    private:
+    BaseHandler *handler_;
+    int id_;
+
+    Handle(BaseHandler *h, int id) : handler_(h), id_(id) {}
 };
 
 /**
@@ -85,116 +96,118 @@ struct [[nodiscard]] Handle {
  */
 template <typename ...ARGS>
 struct Handler : BaseHandler {
-	Handler() {}
-	~Handler() {
-		// Ensure all thread pool jobs are done
-		while (jobs_ > 0 && ftl::pool.size() > 0) std::this_thread::sleep_for(std::chrono::milliseconds(2));
-	}
-
-	/**
-	 * Add a new callback function. It returns a `Handle` object that must
-	 * remain in scope, the destructor of the `Handle` will remove the callback.
-	 */
-	Handle on(const std::function<bool(ARGS...)> &f) {
-		std::unique_lock<std::mutex> lk(mutex_);
-		int id = id_++;
-		callbacks_[id] = f;
-		return make_handle(this, id);
-	}
-
-	/**
-	 * Safely trigger all callbacks. Note that `Handler` is locked when
-	 * triggering so callbacks cannot make modifications to it or they will
-	 * lock up. To remove a callback, return false from the callback, else
-	 * return true.
-	 */
-	void trigger(ARGS ...args) {
-		bool hadFault = false;
-		std::unique_lock<std::mutex> lk(mutex_);
-		for (auto i=callbacks_.begin(); i!=callbacks_.end(); ) {
-			bool keep = true;
-			try {
-				keep = i->second(args...);
-			} catch(...) {
-				hadFault = true;
-			}
-			if (!keep) i = callbacks_.erase(i);
-			else ++i;
-		}
-		if (hadFault) throw FTL_Error("Callback exception");
-	}
-
-	/**
-	 * Call all the callbacks in another thread. The callbacks are done in a
-	 * single thread, not in parallel.
-	 */
-	void triggerAsync(ARGS ...args) {
-		++jobs_;
-		ftl::pool.push([this, args...](int id) {
-			bool hadFault = false;
-			std::unique_lock<std::mutex> lk(mutex_);
-			for (auto i=callbacks_.begin(); i!=callbacks_.end(); ) {
-				bool keep = true;
-				try {
-					keep = i->second(args...);
-				} catch (...) {
-					hadFault = true;
-				}
-				if (!keep) i = callbacks_.erase(i);
-				else ++i;
-			}
-			--jobs_;
-			if (hadFault) throw FTL_Error("Callback exception");
-		});
-	}
-
-	/**
-	 * Each callback is called in its own thread job. Note: the return value
-	 * of the callback is ignored in this case and does not allow callback
-	 * removal via the return value.
-	 */
-	void triggerParallel(ARGS ...args) {
-		std::unique_lock<std::mutex> lk(mutex_);
-		jobs_ += callbacks_.size();
-		for (auto i=callbacks_.begin(); i!=callbacks_.end(); ++i) {
-			ftl::pool.push([this, f = i->second, args...](int id) {
-				try {
-					f(args...);
-				} catch (const ftl::exception &e) {
-					--jobs_;
-					throw e;
-				}
-				--jobs_;
-			});
-		}
-	}
-
-	/**
-	 * Remove a callback using its `Handle`. This is equivalent to allowing the
-	 * `Handle` to be destroyed or cancelled.
-	 */
-	void remove(const Handle &h) override {
-		{
-			std::unique_lock<std::mutex> lk(mutex_);
-			callbacks_.erase(h.id());
-		}
-		// Make sure any possible call to removed callback has finished.
-		while (jobs_ > 0 && ftl::pool.size() > 0) std::this_thread::sleep_for(std::chrono::milliseconds(2));
-	}
-
-	void removeUnsafe(const Handle &h) override {
-		callbacks_.erase(h.id());
-		// Make sure any possible call to removed callback has finished.
-		while (jobs_ > 0 && ftl::pool.size() > 0) std::this_thread::sleep_for(std::chrono::milliseconds(2));
-	}
-
-	void clear() {
-		callbacks_.clear();
-	}
-
-	private:
-	std::unordered_map<int, std::function<bool(ARGS...)>> callbacks_;
-	std::atomic_int jobs_=0;
+    Handler() {}
+    ~Handler() {
+        // Ensure all thread pool jobs are done
+        while (jobs_ > 0 && ftl::pool.size() > 0) std::this_thread::sleep_for(std::chrono::milliseconds(2));
+    }
+
+    /**
+     * Add a new callback function. It returns a `Handle` object that must
+     * remain in scope, the destructor of the `Handle` will remove the callback.
+     */
+    Handle on(const std::function<bool(ARGS...)> &f) {
+        std::unique_lock<std::mutex> lk(mutex_);
+        int id = id_++;
+        callbacks_[id] = f;
+        return make_handle(this, id);
+    }
+
+    /**
+     * Safely trigger all callbacks. Note that `Handler` is locked when
+     * triggering so callbacks cannot make modifications to it or they will
+     * lock up. To remove a callback, return false from the callback, else
+     * return true.
+     */
+    void trigger(ARGS ...args) {
+        bool hadFault = false;
+        std::unique_lock<std::mutex> lk(mutex_);
+        for (auto i = callbacks_.begin(); i != callbacks_.end(); ) {
+            bool keep = true;
+            try {
+                keep = i->second(args...);
+            } catch(...) {
+                hadFault = true;
+            }
+            if (!keep) i = callbacks_.erase(i);
+            else
+                ++i;
+        }
+        if (hadFault) throw FTL_Error("Callback exception");
+    }
+
+    /**
+     * Call all the callbacks in another thread. The callbacks are done in a
+     * single thread, not in parallel.
+     */
+    void triggerAsync(ARGS ...args) {
+        ++jobs_;
+        ftl::pool.push([this, args...](int id) {
+            bool hadFault = false;
+            std::unique_lock<std::mutex> lk(mutex_);
+            for (auto i = callbacks_.begin(); i != callbacks_.end(); ) {
+                bool keep = true;
+                try {
+                    keep = i->second(args...);
+                } catch (...) {
+                    hadFault = true;
+                }
+                if (!keep) i = callbacks_.erase(i);
+                else
+                    ++i;
+            }
+            --jobs_;
+            if (hadFault) throw FTL_Error("Callback exception");
+        });
+    }
+
+    /**
+     * Each callback is called in its own thread job. Note: the return value
+     * of the callback is ignored in this case and does not allow callback
+     * removal via the return value.
+     */
+    void triggerParallel(ARGS ...args) {
+        std::unique_lock<std::mutex> lk(mutex_);
+        jobs_ += callbacks_.size();
+        for (auto i = callbacks_.begin(); i != callbacks_.end(); ++i) {
+            ftl::pool.push([this, f = i->second, args...](int id) {
+                try {
+                    f(args...);
+                } catch (const ftl::exception &e) {
+                    --jobs_;
+                    throw e;
+                }
+                --jobs_;
+            });
+        }
+    }
+
+    /**
+     * Remove a callback using its `Handle`. This is equivalent to allowing the
+     * `Handle` to be destroyed or cancelled.
+     */
+    void remove(const Handle &h) override {
+        {
+            std::unique_lock<std::mutex> lk(mutex_);
+            callbacks_.erase(h.id());
+        }
+        // Make sure any possible call to removed callback has finished.
+        while (jobs_ > 0 && ftl::pool.size() > 0) std::this_thread::sleep_for(std::chrono::milliseconds(2));
+    }
+
+    void removeUnsafe(const Handle &h) override {
+        callbacks_.erase(h.id());
+        // Make sure any possible call to removed callback has finished.
+        while (jobs_ > 0 && ftl::pool.size() > 0) std::this_thread::sleep_for(std::chrono::milliseconds(2));
+    }
+
+    void clear() {
+        callbacks_.clear();
+    }
+
+ private:
+    std::unordered_map<int, std::function<bool(ARGS...)>> callbacks_;
+    std::atomic_int jobs_ = 0;
 };
 
 /**
@@ -205,61 +218,58 @@ struct Handler : BaseHandler {
  */
 template <typename ...ARGS>
 struct SingletonHandler : BaseHandler {
-	/**
-	 * Add a new callback function. It returns a `Handle` object that must
-	 * remain in scope, the destructor of the `Handle` will remove the callback.
-	 */
-	[[nodiscard]] Handle on(const std::function<bool(ARGS...)> &f) {
-		std::unique_lock<std::mutex> lk(mutex_);
-		if (callback_) throw FTL_Error("Callback already bound");
-		callback_ = f;
-		return make_handle(this, id_++);
-	}
-
-	/**
-	 * Safely trigger all callbacks. Note that `Handler` is locked when
-	 * triggering so callbacks cannot make modifications to it or they will
-	 * lock up. To remove a callback, return false from the callback, else
-	 * return true.
-	 */
-	bool trigger(ARGS ...args) {
-		std::unique_lock<std::mutex> lk(mutex_);
-		if (callback_) {
-			bool keep = callback_(std::forward<ARGS>(args)...);
-			if (!keep) callback_ = nullptr;
-			return keep;
-		} else {
-			return false;
-		}
-		//} catch (const std::exception &e) {
-		//	LOG(ERROR) << "Exception in callback: " << e.what();
-		//}
-	}
-
-	/**
-	 * Remove a callback using its `Handle`. This is equivalent to allowing the
-	 * `Handle` to be destroyed or cancelled. If the handle does not match the
-	 * currently bound callback then the callback is not removed.
-	 */
-	void remove(const Handle &h) override {
-		std::unique_lock<std::mutex> lk(mutex_);
-		if (h.id() == id_-1) callback_ = nullptr;
-	}
-
-	void removeUnsafe(const Handle &h) override {
-		if (h.id() == id_-1) callback_ = nullptr;
-	}
-
-	void reset() { callback_ = nullptr; }
-
-	operator bool() const { return (bool)callback_; }
-
-	private:
-	std::function<bool(ARGS...)> callback_;
+    /**
+     * Add a new callback function. It returns a `Handle` object that must
+     * remain in scope, the destructor of the `Handle` will remove the callback.
+     */
+    [[nodiscard]] Handle on(const std::function<bool(ARGS...)> &f) {
+        std::unique_lock<std::mutex> lk(mutex_);
+        if (callback_) throw FTL_Error("Callback already bound");
+        callback_ = f;
+        return make_handle(this, id_++);
+    }
+
+    /**
+     * Safely trigger all callbacks. Note that `Handler` is locked when
+     * triggering so callbacks cannot make modifications to it or they will
+     * lock up. To remove a callback, return false from the callback, else
+     * return true.
+     */
+    bool trigger(ARGS ...args) {
+        std::unique_lock<std::mutex> lk(mutex_);
+        if (callback_) {
+            bool keep = callback_(std::forward<ARGS>(args)...);
+            if (!keep) callback_ = nullptr;
+            return keep;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Remove a callback using its `Handle`. This is equivalent to allowing the
+     * `Handle` to be destroyed or cancelled. If the handle does not match the
+     * currently bound callback then the callback is not removed.
+     */
+    void remove(const Handle &h) override {
+        std::unique_lock<std::mutex> lk(mutex_);
+        if (h.id() == id_-1) callback_ = nullptr;
+    }
+
+    void removeUnsafe(const Handle &h) override {
+        if (h.id() == id_-1) callback_ = nullptr;
+    }
+
+    void reset() { callback_ = nullptr; }
+
+    operator bool() const { return static_cast<bool>(callback_); }
+
+ private:
+    std::function<bool(ARGS...)> callback_;
 };
 
-}
+}  // namespace ftl
 
 ftl::Handle ftl::BaseHandler::make_handle(BaseHandler *h, int id) {
-	return ftl::Handle(h, id);
+    return ftl::Handle(h, id);
 }
diff --git a/include/ftl/protocol.hpp b/include/ftl/protocol.hpp
index 0244c66becea5e0589fce59b32c5e17639120c07..196cadeb85a72d910cd1f2efb44ec347e980f5ba 100644
--- a/include/ftl/protocol.hpp
+++ b/include/ftl/protocol.hpp
@@ -7,6 +7,7 @@
 #pragma once
 
 #include <memory>
+#include <string>
 #include <ftl/uuid.hpp>
 
 namespace ftl {
@@ -20,13 +21,65 @@ class Service;
 void reset();
 
 extern ftl::UUID id;
-}
+}  // namespace protocol
 
+/**
+ * @brief Get the Self object. This may initialise the internal system when
+ * first called. A Self object allows for the overall control of the network
+ * and general RPC functionality between hosts. If this is called multiple
+ * times then the same internal object is returned, it is a singleton.
+ * 
+ * @return std::shared_ptr<ftl::protocol::Self> 
+ */
 std::shared_ptr<ftl::protocol::Self> getSelf();
+
+/**
+ * @brief Create a secondary Self object. Mostly for testing purposes, this
+ * allows additional instances to be created of the otherwise singleton class.
+ * 
+ * @return std::shared_ptr<ftl::protocol::Self> 
+ */
 std::shared_ptr<ftl::protocol::Self> createDummySelf();
+
+/**
+ * @brief Set the web service URI to use. There should be a single connection
+ * to a web service that provides additional management functionality beyond
+ * a typical node. By calling this function the system is informed about where
+ * to ask about certain resources.
+ * 
+ * @param uri A websocket URI, either WS or WSS protocol.
+ * @return A node instance for the service
+ */
 std::shared_ptr<ftl::protocol::Service> setServiceProvider(const std::string &uri);
+
+/**
+ * @brief Connect to another machine. This uses the singleton Self instance, however,
+ * it is possible to also connect from another secondary Self instance by
+ * using a member function.
+ * 
+ * @param uri A TCP URI with the address and port of another machine.
+ * @return std::shared_ptr<ftl::protocol::Node> 
+ */
 std::shared_ptr<ftl::protocol::Node> connectNode(const std::string &uri);
+
+/**
+ * @brief Host a new stream. The URI must be either a file or an FTL protocol.
+ * A file stream opened by this function will be write only, and a network
+ * stream will broadcast itself as a newly available source.
+ * 
+ * @param uri Either file:// or ftl://
+ * @return std::shared_ptr<ftl::protocol::Stream> 
+ */
 std::shared_ptr<ftl::protocol::Stream> createStream(const std::string &uri);
+
+/**
+ * @brief Open an existing stream. This can be a file or a network stream.
+ * A file stream will be opened readonly, and a network stream will attempt
+ * to find the stream on the local network or using the web service.
+ * 
+ * @param uri Either file:// or ftl://
+ * @return std::shared_ptr<ftl::protocol::Stream> 
+ */
 std::shared_ptr<ftl::protocol::Stream> getStream(const std::string &uri);
 
-}
+}  // namespace ftl
diff --git a/include/ftl/protocol/broadcaster.hpp b/include/ftl/protocol/broadcaster.hpp
index 4e404579b4b116dafb04350c2c435c86e8ededbc..ec768bc96e495dd7a9e952ac0171a94c81caa2ed 100644
--- a/include/ftl/protocol/broadcaster.hpp
+++ b/include/ftl/protocol/broadcaster.hpp
@@ -1,7 +1,14 @@
+/**
+ * @file broadcaster.hpp
+ * @copyright Copyright (c) 2022 University of Turku, MIT License
+ * @author Nicolas Pope
+ */
+
 #pragma once
 
-#include <ftl/protocol/streams.hpp>
 #include <list>
+#include <memory>
+#include <ftl/protocol/streams.hpp>
 
 namespace ftl {
 namespace protocol {
@@ -12,50 +19,49 @@ namespace protocol {
  * packets.
  */
 class Broadcast : public Stream {
-	public:
-	explicit Broadcast();
-	virtual ~Broadcast();
-
-	void add(const std::shared_ptr<Stream> &);
-	void remove(const std::shared_ptr<Stream> &);
-	void clear();
+ public:
+    Broadcast();
+    virtual ~Broadcast();
 
-	bool post(const ftl::protocol::StreamPacket &, const ftl::protocol::Packet &) override;
+    void add(const std::shared_ptr<Stream> &);
+    void remove(const std::shared_ptr<Stream> &);
+    void clear();
 
-	bool begin() override;
-	bool end() override;
-	bool active() override;
+    bool post(const ftl::protocol::StreamPacket &, const ftl::protocol::Packet &) override;
 
-	void reset() override;
+    bool begin() override;
+    bool end() override;
+    bool active() override;
 
-	void refresh() override;
+    void reset() override;
 
-	std::list<std::shared_ptr<Stream>> streams() const;
+    void refresh() override;
 
-	void setProperty(ftl::protocol::StreamProperty opt, std::any value) override;
+    std::list<std::shared_ptr<Stream>> streams() const;
 
-	std::any getProperty(ftl::protocol::StreamProperty opt) override;
+    void setProperty(ftl::protocol::StreamProperty opt, std::any value) override;
 
-	bool supportsProperty(ftl::protocol::StreamProperty opt) override;
+    std::any getProperty(ftl::protocol::StreamProperty opt) override;
 
-	bool enable(FrameID id) override;
+    bool supportsProperty(ftl::protocol::StreamProperty opt) override;
 
-	bool enable(FrameID id, ftl::protocol::Channel channel) override;
+    bool enable(FrameID id) override;
 
-	bool enable(FrameID id, const ftl::protocol::ChannelSet &channels) override;
+    bool enable(FrameID id, ftl::protocol::Channel channel) override;
 
-	StreamType type() const override;
+    bool enable(FrameID id, const ftl::protocol::ChannelSet &channels) override;
 
-	private:
+    StreamType type() const override;
 
-	struct StreamEntry {
-		std::shared_ptr<Stream> stream;
-		ftl::Handle handle;
-		ftl::Handle req_handle;
-		ftl::Handle avail_handle;
-	};
+ private:
+    struct StreamEntry {
+        std::shared_ptr<Stream> stream;
+        ftl::Handle handle;
+        ftl::Handle req_handle;
+        ftl::Handle avail_handle;
+    };
 
-	std::list<StreamEntry> streams_;
+    std::list<StreamEntry> streams_;
 };
 
 }
diff --git a/include/ftl/protocol/channelSet.hpp b/include/ftl/protocol/channelSet.hpp
index 2f2485d05d7a8a70377f10e4301376ce2aa14485..8d0a7220085d229ff00141490aa5c28ea4954e35 100644
--- a/include/ftl/protocol/channelSet.hpp
+++ b/include/ftl/protocol/channelSet.hpp
@@ -6,8 +6,8 @@
 
 #pragma once
 
-#include <ftl/protocol/channels.hpp>
 #include <unordered_set>
+#include <ftl/protocol/channels.hpp>
 
 namespace ftl {
 namespace protocol {
@@ -20,26 +20,26 @@ ftl::protocol::ChannelSet operator&(const ftl::protocol::ChannelSet &a, const ft
 ftl::protocol::ChannelSet operator-(const ftl::protocol::ChannelSet &a, const ftl::protocol::ChannelSet &b);
 
 inline ftl::protocol::ChannelSet &operator+=(ftl::protocol::ChannelSet &t, ftl::protocol::Channel c) {
-	t.insert(c);
-	return t;
+    t.insert(c);
+    return t;
 }
 
 inline ftl::protocol::ChannelSet &operator-=(ftl::protocol::ChannelSet &t, ftl::protocol::Channel c) {
-	t.erase(c);
-	return t;
+    t.erase(c);
+    return t;
 }
 
 inline ftl::protocol::ChannelSet operator+(const ftl::protocol::ChannelSet &t, ftl::protocol::Channel c) {
-	auto r = t;
-	r.insert(c);
-	return r;
+    auto r = t;
+    r.insert(c);
+    return r;
 }
 
 inline ftl::protocol::ChannelSet operator+(ftl::protocol::Channel a, ftl::protocol::Channel b) {
-	std::unordered_set<ftl::protocol::Channel> r;
-	r.insert(a);
-	r.insert(b);
-	return r;
+    std::unordered_set<ftl::protocol::Channel> r;
+    r.insert(a);
+    r.insert(b);
+    return r;
 }
 
 bool operator!=(const ftl::protocol::ChannelSet &a, const ftl::protocol::ChannelSet &b);
diff --git a/include/ftl/protocol/channelUtils.hpp b/include/ftl/protocol/channelUtils.hpp
index 218ea6ff78eefd4dad395a97953f58505a8d3a99..4b33794f80bd18919f821b293c1c180dcb5f4a6c 100644
--- a/include/ftl/protocol/channelUtils.hpp
+++ b/include/ftl/protocol/channelUtils.hpp
@@ -1,13 +1,20 @@
+/**
+ * @file channelUtils.hpp
+ * @copyright Copyright (c) 2020 University of Turku, MIT License
+ * @author Nicolas Pope
+ */
+
 #pragma once
 
+#include <string>
 #include <ftl/protocol/channels.hpp>
 
 namespace ftl {
 namespace protocol {
 
-inline bool isVideo(Channel c) { return (int)c < 32; };
-inline bool isAudio(Channel c) { return (int)c >= 32 && (int)c < 64; };
-inline bool isData(Channel c) { return (int)c >= 64; };
+inline bool isVideo(Channel c) { return static_cast<int>(c) < 32; }
+inline bool isAudio(Channel c) { return static_cast<int>(c) >= 32 && static_cast<int>(c) < 64; }
+inline bool isData(Channel c) { return static_cast<int>(c) >= 64; }
 
 /** Obtain a string name for channel. */
 std::string name(Channel c);
@@ -17,17 +24,16 @@ int type(Channel c);
 
 /** @deprecated */
 inline bool isFloatChannel(ftl::codecs::Channel chan) {
-	switch (chan) {
-	case Channel::GroundTruth:
-	case Channel::Depth		:
-	//case Channel::Normals   :
-	case Channel::Confidence:
-	case Channel::Flow      :
-	case Channel::Density:
-	case Channel::Energy	: return true;
-	default					: return false;
-	}
+    switch (chan) {
+    case Channel::GroundTruth  :
+    case Channel::Depth        :
+    case Channel::Confidence   :
+    case Channel::Flow         :
+    case Channel::Density      :
+    case Channel::Energy       : return true;
+    default                    : return false;
+    }
 }
 
-}
-}
+}  // namespace protocol
+}  // namespace ftl
diff --git a/include/ftl/protocol/channels.hpp b/include/ftl/protocol/channels.hpp
index 5dc74bccf3d01f3fea8cbac077d391762b743b1b..49a4e1763e41c230b868eaa4675348c2d8a818e7 100644
--- a/include/ftl/protocol/channels.hpp
+++ b/include/ftl/protocol/channels.hpp
@@ -7,129 +7,126 @@
 #pragma once
 
 #include <bitset>
-//#include <msgpack.hpp>
 
 namespace ftl {
 namespace protocol {
 
 /** Frame channel identifier. */
 enum struct Channel : int {
-	/* Video Channels */
-	kNone			= -1,
-	kColour			= 0,	// 8UC3 or 8UC4
-	kLeft			= 0,
-	kDepth			= 1,	// 32S or 32F
-	kRight			= 2,	// 8UC3 or 8UC4
-	kColour2		= 2,
-	kDepth2			= 3,
-	kDeviation		= 4,
-	kScreen			= 4,	// 16SC2
-	kNormals		= 5,	// 16FC4
-	kWeights		= 6,	// short
-	kConfidence		= 7,	// 32F
-	kContribution	= 7,	// 32F
-	kEnergyVector	= 8,	// 32FC4
-	kFlow			= 9,	// 16SC2
-	kFlow2			= 10,	// 16SC2
-	kEnergy			= 10,	// 32F
-	kMask			= 11,	// 32U
-	kDensity		= 12,	// 32F
-	kSupport1		= 13,	// 8UC4 (currently)
-	kSupport2		= 14,	// 8UC4 (currently)
-	kSegmentation	= 15,	// 32S?
-	kNormals2		= 16,	// 16FC4
-	kUNUSED1		= 17,	
-	kDisparity		= 18,
-	kSmoothing		= 19,	// 32F
-	kUNUSED2		= 20,
-	kOverlay		= 21,   // 8UC4
-	kGroundTruth	= 22,	// 32F
-
-	/* Audio Channels */
-	kAudioMono		= 32,	// Deprecated, will always be stereo
-	kAudioStereo	= 33,
-	kAudio			= 33,
-
-	/* Special data channels */
-	kConfiguration	= 64,	// JSON Data
-	kSettings1		= 65,
-	kCalibration	= 65,	// Camera Parameters Object
-	kPose			= 66,	// Eigen::Matrix4d, camera transform
-	kSettings2		= 67,
-	kCalibration2	= 67,	// Right camera parameters
-	kIndex           = 68,
-	kControl		= 69,	// For stream and encoder control
-	kSettings3		= 70,
-	kMetaData		= 71,	// Map of string pairs (key, value)
-	kCapabilities	= 72,	// Unordered set of int capabilities
-	kCalibrationData = 73,	// Just for stereo intrinsics/extrinsics etc
-	kThumbnail		= 74,	// Small JPG thumbnail, sometimes updated
-	kOverlaySelect	= 75,	// Choose what to have in the overlay channel
-	kStartTime		= 76,	// Stream start timestamp
-	kUser			= 77,	// User currently controlling the stream
-
-	kAccelerometer	= 90,	// Eigen::Vector3f
-	kGyroscope 		= 91,	// Eigen::Vector3f
-
-	/* Camera Options */
-	kBrightness		= 100,
-	kContrast		= 101,
-	kExposure		= 102,
-	kGain			= 103,
-	kWhiteBalance	= 104,
-	kAutoExposure	= 105,
-	kAutoWhiteBalance = 106,
-	kCameraTemperature = 107,
-
-	/* Realsense Options */
-	kRS2_LaserPower	= 150,
-	kRS2_MinDistance = 151,
-	kRS2_MaxDistance = 152,
-	kRS2_InterCamSync = 153,
-	kRS2_PostSharpening = 154,
-
-	/* Pylon Options 200 */
-
-	/* Audio Settings 300 */
-
-	/* Renderer Settings 400 */
-	kRenderer_CameraType		= 400,	// stereo, normal, tile
-	kRenderer_Visualisation		= 401,	// Pointcloud, mesh, other
-	kRenderer_Engine			= 402,	// OpenGL, CUDA, other
-	kRenderer_FPS				= 403,	// Frames per second
-	kRenderer_View				= 404,	// Fixed viewpoint to one source
-	kRenderer_Channel			= 405,	// Select overlay channel,
-	kRenderer_Opacity			= 406,	// Opacity of overlay channel
-	kRenderer_Sources			= 407,	// Which source devices to use
-	kRenderer_Projection		= 408,	// 0 = normal, 1 = ortho, 2 = equirect
-	kRenderer_Background		= 409,	// Background colour
-	kRenderer_ShowBadColour		= 420,
-	kRenderer_CoolEffect		= 421,
-	kRenderer_EffectColour		= 422,
-	kRenderer_ShowColourWeights	= 423,
-	kRenderer_TriangleLimit		= 424,
-	kRenderer_DisconDisparities	= 425,
-	kRenderer_NormalWeightColour = 426,
-	kRenderer_ChannelWeights	= 427,
-	kRenderer_AccumFunc			= 428,
-
-	/* Pipeline Settings */
-	kPipeline_Enable			= 500,
-	kPipeline_EnableMVMLS		= 501,
-	kPipeline_EnableAruco		= 502,
-
-	/* Custom / user data channels */
-	kData			= 2048,	// Do not use
-	kEndFrame		= 2048, // Signify the last packet
-	kFaces			= 2049, // Data about detected faces
-	kTransforms		= 2050,	// Transformation matrices for framesets
-	kShapes3D		= 2051,	// Labeled 3D shapes
-	kMessages		= 2052,	// Vector of Strings
-	kTouch			= 2053, // List of touch data type (each touch point)
-	kPipelines		= 2054,	// List of pipline URIs that have been applied
+    /* Video Channels */
+    kNone           = -1,
+    kColour         = 0,    // 8UC3 or 8UC4
+    kLeft           = 0,
+    kDepth          = 1,    // 32S or 32F
+    kRight          = 2,    // 8UC3 or 8UC4
+    kColour2        = 2,
+    kDepth2         = 3,
+    kDeviation      = 4,
+    kScreen         = 4,    // 16SC2
+    kNormals        = 5,    // 16FC4
+    kWeights        = 6,    // short
+    kConfidence     = 7,    // 32F
+    kContribution   = 7,    // 32F
+    kEnergyVector   = 8,    // 32FC4
+    kFlow           = 9,    // 16SC2
+    kFlow2          = 10,   // 16SC2
+    kEnergy         = 10,   // 32F
+    kMask           = 11,   // 32U
+    kDensity        = 12,   // 32F
+    kSupport1       = 13,   // 8UC4 (currently)
+    kSupport2       = 14,   // 8UC4 (currently)
+    kSegmentation   = 15,   // 32S?
+    kNormals2       = 16,   // 16FC4
+    kUNUSED1        = 17,
+    kDisparity      = 18,
+    kSmoothing      = 19,   // 32F
+    kUNUSED2        = 20,
+    kOverlay        = 21,   // 8UC4
+    kGroundTruth    = 22,   // 32F
+
+    /* Audio Channels */
+    kAudioMono      = 32,   // Deprecated, will always be stereo
+    kAudioStereo    = 33,
+    kAudio          = 33,
+
+    /* Special data channels */
+    kConfiguration    = 64,   // JSON Data
+    kSettings1        = 65,
+    kCalibration      = 65,   // Camera Parameters Object
+    kPose             = 66,   // Eigen::Matrix4d, camera transform
+    kSettings2        = 67,
+    kCalibration2     = 67,   // Right camera parameters
+    kIndex            = 68,
+    kControl          = 69,   // For stream and encoder control
+    kSettings3        = 70,
+    kMetaData         = 71,   // Map of string pairs (key, value)
+    kCapabilities     = 72,   // Unordered set of int capabilities
+    kCalibrationData  = 73,  // Just for stereo intrinsics/extrinsics etc
+    kThumbnail        = 74,   // Small JPG thumbnail, sometimes updated
+    kOverlaySelect    = 75,   // Choose what to have in the overlay channel
+    kStartTime        = 76,   // Stream start timestamp
+    kUser             = 77,   // User currently controlling the stream
+
+    kAccelerometer    = 90,   // Eigen::Vector3f
+    kGyroscope        = 91,   // Eigen::Vector3f
+
+    /* Camera Options */
+    kBrightness          = 100,
+    kContrast            = 101,
+    kExposure            = 102,
+    kGain                = 103,
+    kWhiteBalance        = 104,
+    kAutoExposure        = 105,
+    kAutoWhiteBalance    = 106,
+    kCameraTemperature   = 107,
+
+    /* Realsense Options */
+    kRS2_LaserPower       = 150,
+    kRS2_MinDistance      = 151,
+    kRS2_MaxDistance      = 152,
+    kRS2_InterCamSync     = 153,
+    kRS2_PostSharpening   = 154,
+
+    /* Pylon Options 200 */
+
+    /* Audio Settings 300 */
+
+    /* Renderer Settings 400 */
+    kRenderer_CameraType          = 400,  // stereo, normal, tile
+    kRenderer_Visualisation       = 401,  // Pointcloud, mesh, other
+    kRenderer_Engine              = 402,  // OpenGL, CUDA, other
+    kRenderer_FPS                 = 403,  // Frames per second
+    kRenderer_View                = 404,  // Fixed viewpoint to one source
+    kRenderer_Channel             = 405,  // Select overlay channel,
+    kRenderer_Opacity             = 406,  // Opacity of overlay channel
+    kRenderer_Sources             = 407,  // Which source devices to use
+    kRenderer_Projection          = 408,  // 0 = normal, 1 = ortho, 2 = equirect
+    kRenderer_Background          = 409,  // Background colour
+    kRenderer_ShowBadColour       = 420,
+    kRenderer_CoolEffect          = 421,
+    kRenderer_EffectColour        = 422,
+    kRenderer_ShowColourWeights   = 423,
+    kRenderer_TriangleLimit       = 424,
+    kRenderer_DisconDisparities   = 425,
+    kRenderer_NormalWeightColour  = 426,
+    kRenderer_ChannelWeights      = 427,
+    kRenderer_AccumFunc           = 428,
+
+    /* Pipeline Settings */
+    kPipeline_Enable          = 500,
+    kPipeline_EnableMVMLS     = 501,
+    kPipeline_EnableAruco     = 502,
+
+    /* Custom / user data channels */
+    kData           = 2048,  // Do not use
+    kEndFrame       = 2048,  // Signify the last packet
+    kFaces          = 2049,  // Data about detected faces
+    kTransforms     = 2050,  // Transformation matrices for framesets
+    kShapes3D       = 2051,  // Labeled 3D shapes
+    kMessages       = 2052,  // Vector of Strings
+    kTouch          = 2053,  // List of touch data type (each touch point)
+    kPipelines      = 2054,  // List of pipline URIs that have been applied
 };
 
-}
-}
-
-//MSGPACK_ADD_ENUM(ftl::codecs::Channel);
+}  // namespace protocol
+}  // namespace ftl
diff --git a/include/ftl/protocol/codecs.hpp b/include/ftl/protocol/codecs.hpp
index 53556443099bc0135759458d0faece86e438112a..67762b2087cac624da53a3a6530ab8b606361811 100644
--- a/include/ftl/protocol/codecs.hpp
+++ b/include/ftl/protocol/codecs.hpp
@@ -7,7 +7,7 @@
 #pragma once
 
 #include <cstdint>
-//#include <msgpack.hpp>
+#include <utility>
 
 namespace ftl {
 
@@ -17,42 +17,40 @@ namespace ftl {
  */
 namespace protocol {
 
-static constexpr uint8_t kFlagRequest = 0x01;		///< Used for empty data packets to mark a request for data
-static constexpr uint8_t kFlagCompleted = 0x02;		///< Last packet for timestamp
+static constexpr uint8_t kFlagRequest = 0x01;    ///< Used for empty data packets to mark a request for data
+static constexpr uint8_t kFlagCompleted = 0x02;  ///< Last packet for timestamp
 static constexpr uint8_t kFlagReset = 0x04;
 
 /**
  * Compression format used.
  */
 enum struct Codec : uint8_t {
-	/* Video (image) codecs */
-	kJPG = 0,
-	kPNG,
-	kH264,
-	kHEVC,  			// H265
-	kH264Lossless,
-	kHEVCLossLess,
-
-	/* Audio codecs */
-	kWave=32,
-	kOPUS,
-
-	/* Data "codecs" */
-	kJSON = 100,	// A JSON string
-	kCalibration,	// Camera parameters object [deprecated]
-	kPose,			// 4x4 eigen matrix [deprecated]
-	kMsgPack,
-	kString,		// Null terminated string
-	kRaw,			// Some unknown binary format
-
-	kInvalid = 254,
-	kAny = 255
+    /* Video (image) codecs */
+    kJPG = 0,
+    kPNG,
+    kH264,
+    kHEVC,          // H265
+    kH264Lossless,
+    kHEVCLossLess,
+
+    /* Audio codecs */
+    kWave = 32,
+    kOPUS,
+
+    /* Data "codecs" */
+    kJSON = 100,    // A JSON string
+    kCalibration,   // Camera parameters object [deprecated]
+    kPose,          // 4x4 eigen matrix [deprecated]
+    kMsgPack,
+    kString,        // Null terminated string
+    kRaw,           // Some unknown binary format
+
+    kInvalid = 254,
+    kAny = 255
 };
 
 /** Given a frame count, return a width x height tile configuration. */
-std::pair<int,int> chooseTileConfig(int size);
+std::pair<int, int> chooseTileConfig(int size);
 
-}  // namespace codecs
+}  // namespace protocol
 }  // namespace ftl
-
-//MSGPACK_ADD_ENUM(ftl::codecs::codec_t);
diff --git a/include/ftl/protocol/error.hpp b/include/ftl/protocol/error.hpp
index 708ed388ea73330d85b1c9fae3b5dc372ce05b34..3f172027407e88c485754fb66dda2f37a0b24437 100644
--- a/include/ftl/protocol/error.hpp
+++ b/include/ftl/protocol/error.hpp
@@ -1,8 +1,18 @@
+/**
+ * @file error.hpp
+ * @copyright Copyright (c) 2022 University of Turku, MIT License
+ * @author Nicolas Pope
+ */
+
 #pragma once
 
 namespace ftl {
 namespace protocol {
 
+/**
+ * @brief Error codes for asynchronous error events.
+ * 
+ */
 enum struct Error {
     kNoError = 0,
     kUnknown = 1,
@@ -22,5 +32,5 @@ enum struct Error {
     kBadURI
 };
 
-}
-}
+}  // namespace protocol
+}  // namespace ftl
diff --git a/include/ftl/protocol/frameid.hpp b/include/ftl/protocol/frameid.hpp
index 39610ca3e63f7224e0d0ef27642f8c2c966c2d9e..643b1a1e8a1f012478f6fdb765f9bbe5bcc64962 100644
--- a/include/ftl/protocol/frameid.hpp
+++ b/include/ftl/protocol/frameid.hpp
@@ -1,3 +1,9 @@
+/**
+ * @file frameid.hpp
+ * @copyright Copyright (c) 2022 University of Turku, MIT License
+ * @author Nicolas Pope
+ */
+
 #pragma once
 
 #include <cinttypes>
@@ -11,45 +17,46 @@ namespace protocol {
  * frames cannot be duplicated.
  */
 struct FrameID {
-	uint32_t id;
-
-	/**
-	 * Frameset ID for this frame.
-	 */
-	inline unsigned int frameset() const { return id >> 8; }
-
-	/**
-	 * Frame index within the frameset. This will correspond to the vector
-	 * index in the frameset object.
-	 */
-	inline unsigned int source() const { return id & 0xff; }
-
-	/**
-	 * The packed int with both frameset ID and index.
-	 */
-	operator uint32_t() const { return id; }
-
-	inline FrameID &operator=(int v) { id = v; return *this; }
-
-	/**
-	 * Create a frame ID using a frameset id and a source number.
-	 * @param fs Frameset id
-	 * @param s Source number inside frameset
-	 */
-	FrameID(unsigned int fs, unsigned int s) : id((fs << 8) + (s & 0xff) ) {}
-	explicit FrameID(uint32_t x) : id(x) {}
-	FrameID() : id(0) {}
+    uint32_t id;
+
+    /**
+     * Frameset ID for this frame.
+     */
+    inline unsigned int frameset() const { return id >> 8; }
+
+    /**
+     * Frame index within the frameset. This will correspond to the vector
+     * index in the frameset object.
+     */
+    inline unsigned int source() const { return id & 0xff; }
+
+    /**
+     * The packed int with both frameset ID and index.
+     */
+    operator uint32_t() const { return id; }
+
+    inline FrameID &operator=(int v) {
+        id = v;
+        return *this;
+    }
+
+    /**
+     * Create a frame ID using a frameset id and a source number.
+     * @param fs Frameset id
+     * @param s Source number inside frameset
+     */
+    FrameID(unsigned int fs, unsigned int s) : id((fs << 8) + (s & 0xff) ) {}
+    explicit FrameID(uint32_t x) : id(x) {}
+    FrameID() : id(0) {}
 };
 
-}
-}
+}  // namespace protocol
+}  // namespace ftl
 
 // custom specialization of std::hash can be injected in namespace std
 template<>
-struct std::hash<ftl::protocol::FrameID>
-{
-    std::size_t operator()(ftl::protocol::FrameID const& s) const noexcept
-    {
+struct std::hash<ftl::protocol::FrameID> {
+    std::size_t operator()(ftl::protocol::FrameID const& s) const noexcept {
         return std::hash<unsigned int>{}(s.id);
     }
 };
diff --git a/include/ftl/protocol/muxer.hpp b/include/ftl/protocol/muxer.hpp
index 777c276e61e1c9c59af6e0a7f66f1a4e17d092e7..5d934b3ff73e47a74bd9587d7c15f34c342fea98 100644
--- a/include/ftl/protocol/muxer.hpp
+++ b/include/ftl/protocol/muxer.hpp
@@ -1,9 +1,17 @@
-#pragma once
+/**
+ * @file muxer.hpp
+ * @copyright Copyright (c) 2020 University of Turku, MIT License
+ * @author Nicolas Pope
+ */
 
-#include <ftl/protocol/streams.hpp>
+#pragma once
 
 #include <map>
 #include <list>
+#include <memory>
+#include <unordered_map>
+#include <utility>
+#include <ftl/protocol/streams.hpp>
 
 namespace ftl {
 namespace protocol {
@@ -17,65 +25,68 @@ static constexpr size_t kMaxStreams = 5;
  * stream mapping to be registered.
  */
 class Muxer : public Stream {
-	public:
-	explicit Muxer();
-	virtual ~Muxer();
-
-	void add(const std::shared_ptr<Stream> &, int fsid=-1);
-	void remove(const std::shared_ptr<Stream> &);
+ public:
+    Muxer();
+    virtual ~Muxer();
 
-	//bool onPacket(const StreamCallback &) override;
+    void add(const std::shared_ptr<Stream> &, int fsid = -1);
+    void remove(const std::shared_ptr<Stream> &);
 
-	bool post(const ftl::protocol::StreamPacket &, const ftl::protocol::Packet &) override;
+    bool post(const ftl::protocol::StreamPacket &, const ftl::protocol::Packet &) override;
 
-	bool begin() override;
-	bool end() override;
-	bool active() override;
+    bool begin() override;
+    bool end() override;
+    bool active() override;
 
-	void reset() override;
+    void reset() override;
 
-	bool enable(FrameID id) override;
+    bool enable(FrameID id) override;
 
-	bool enable(FrameID id, ftl::protocol::Channel channel) override;
+    bool enable(FrameID id, ftl::protocol::Channel channel) override;
 
-	bool enable(FrameID id, const ftl::protocol::ChannelSet &channels) override;
+    bool enable(FrameID id, const ftl::protocol::ChannelSet &channels) override;
 
-	void setProperty(ftl::protocol::StreamProperty opt, std::any value) override;
+    void setProperty(ftl::protocol::StreamProperty opt, std::any value) override;
 
-	std::any getProperty(ftl::protocol::StreamProperty opt) override;
+    std::any getProperty(ftl::protocol::StreamProperty opt) override;
 
-	bool supportsProperty(ftl::protocol::StreamProperty opt) override;
+    bool supportsProperty(ftl::protocol::StreamProperty opt) override;
 
-	StreamType type() const override;
+    StreamType type() const override;
 
-	std::shared_ptr<Stream> originStream(FrameID) const;
+    /**
+     * @brief Get the stream instance associated with an ID.
+     * 
+     * @return std::shared_ptr<Stream> 
+     */
+    std::shared_ptr<Stream> originStream(FrameID) const;
 
-	private:
-	struct StreamEntry {
-		std::shared_ptr<Stream> stream;
-		ftl::Handle handle;
-		ftl::Handle req_handle;
-		ftl::Handle avail_handle;
-		ftl::Handle err_handle;
-		int id = 0;
-		int fixed_fs = -1;
-	};
+ private:
+    struct StreamEntry {
+        std::shared_ptr<Stream> stream;
+        ftl::Handle handle;
+        ftl::Handle req_handle;
+        ftl::Handle avail_handle;
+        ftl::Handle err_handle;
+        int id = 0;
+        int fixed_fs = -1;
+    };
 
-	std::unordered_map<int, int> fsmap_;
-	std::unordered_map<int, int> sourcecount_;
-	std::unordered_map<int64_t, FrameID> imap_;
-	std::unordered_map<FrameID, std::pair<FrameID, Muxer::StreamEntry*>> omap_;
-	std::list<StreamEntry> streams_;
-	mutable SHARED_MUTEX mutex_;
-	std::atomic_int stream_ids_ = 0;
-	std::atomic_int framesets_ = 0;
+    std::unordered_map<int, int> fsmap_;
+    std::unordered_map<int, int> sourcecount_;
+    std::unordered_map<int64_t, FrameID> imap_;
+    std::unordered_map<FrameID, std::pair<FrameID, Muxer::StreamEntry*>> omap_;
+    std::list<StreamEntry> streams_;
+    mutable SHARED_MUTEX mutex_;
+    std::atomic_int stream_ids_ = 0;
+    std::atomic_int framesets_ = 0;
 
-	/* On packet receive, map to local ID */
-	FrameID _mapFromInput(StreamEntry *, FrameID id);
+    /* On packet receive, map to local ID */
+    FrameID _mapFromInput(StreamEntry *, FrameID id);
 
-	/* On posting, map to output ID */
-	std::pair<FrameID, StreamEntry*> _mapToOutput(FrameID id) const;
+    /* On posting, map to output ID */
+    std::pair<FrameID, StreamEntry*> _mapToOutput(FrameID id) const;
 };
 
-}
-}
+}  // namespace protocol
+}  // namespace ftl
diff --git a/include/ftl/protocol/node.hpp b/include/ftl/protocol/node.hpp
index e34278ebc9cb1bde0f5a5fc0966321c88e2e5be4..b9b3a1deaf8127eb1d7cda0161d50af6c877e988 100644
--- a/include/ftl/protocol/node.hpp
+++ b/include/ftl/protocol/node.hpp
@@ -6,9 +6,9 @@
 
 #pragma once
 
-#include <ftl/uuid.hpp>
-
 #include <memory>
+#include <string>
+#include <ftl/uuid.hpp>
 
 namespace ftl {
 namespace net {
@@ -24,94 +24,96 @@ enum struct NodeType {
 };
 
 enum struct NodeStatus {
-    kInvalid,		// no socket
-    kConnecting,	// socket created, no handshake yet
-    kConnected,		// connection fully established
-    kDisconnected,	// socket closed, reconnect not possible
-    kReconnecting	// socket closed, call reconnect() to try reconnecting
+    kInvalid,       // no socket
+    kConnecting,    // socket created, no handshake yet
+    kConnected,     // connection fully established
+    kDisconnected,  // socket closed, reconnect not possible
+    kReconnecting   // socket closed, call reconnect() to try reconnecting
 };
 
 /**
- * To be constructed using the Universe::connect() method and not to be
- * created directly.
+ * @brief An API wrapper for a network connection. This object provides the
+ * available RPC calls and connection status or control methods. Note that
+ * releasing the shared pointer will not result in connection termination,
+ * it must be closed and then released for the garbage collection to happen.
+ * 
  */
-class Node {	
-	public:
-	/** Peer for outgoing connection: resolve address and connect */
-	explicit Node(const ftl::net::PeerPtr &impl);
-	virtual ~Node();
-	
-	/**
-	 * Close the peer if open. Setting retry parameter to true will initiate
-	 * backoff retry attempts. This is used to deliberately close a connection
-	 * and not for error conditions where different close semantics apply.
-	 * 
-	 * @param retry Should reconnection be attempted?
-	 */
-	void close(bool retry=false);
-
-	bool isConnected() const;
-	/**
-	 * Block until the connection and handshake has completed. You should use
-	 * onConnect callbacks instead of blocking, mostly this is intended for
-	 * the unit tests to keep them synchronous.
-	 * 
-	 * @return True if all connections were successful, false if timeout or error.
-	 */
-	bool waitConnection(int seconds = 1);
-
-	/**
-	 * Make a reconnect attempt. Called internally by Universe object.
-	 */
-	bool reconnect();
-
-	bool isOutgoing() const;
-	
-	/**
-	 * Test if the connection is valid. This returns true in all conditions
-	 * except where the socket has been disconnected permenantly, or was never
-	 * able to connect, perhaps due to an invalid address, or is in middle of a
-	 * reconnect attempt. (Valid states: kConnecting, kConnected)
-	 * 
-	 * Should return true only in cases when valid OS socket exists.
-	 */
-	bool isValid() const;
-	
-	/** node type */
-	virtual NodeType getType() const { return NodeType::kNode; }
-
-	NodeStatus status() const;
-	
-	uint32_t getFTLVersion() const;
-	uint8_t getFTLMajor() const { return getFTLVersion() >> 16; }
-	uint8_t getFTLMinor() const { return (getFTLVersion() >> 8) & 0xFF; }
-	uint8_t getFTLPatch() const { return getFTLVersion() & 0xFF; }
-	
-	/**
-	 * Get the sockets protocol, address and port as a url string. This will be
-	 * the same as the initial connection string on the client.
-	 */
-	std::string getURI() const;
-	
-	/**
-	 * Get the UUID for this peer.
-	 */
-	const ftl::UUID &id() const;
-	
-	/**
-	 * Get the peer id as a string.
-	 */
-	std::string to_string() const;
-
-	void noReconnect();
-
-	unsigned int localID();
-
-	int connectionCount() const;
-
-	protected:
-	ftl::net::PeerPtr peer_;
+class Node {
+ public:
+    /** Peer for outgoing connection: resolve address and connect */
+    explicit Node(const ftl::net::PeerPtr &impl);
+    virtual ~Node();
+
+    /**
+     * Close the peer if open. Setting retry parameter to true will initiate
+     * backoff retry attempts. This is used to deliberately close a connection
+     * and not for error conditions where different close semantics apply.
+     * 
+     * @param retry Should reconnection be attempted?
+     */
+    void close(bool retry = false);
+
+    bool isConnected() const;
+    /**
+     * Block until the connection and handshake has completed. You should use
+     * onConnect callbacks instead of blocking, mostly this is intended for
+     * the unit tests to keep them synchronous.
+     * 
+     * @return True if all connections were successful, false if timeout or error.
+     */
+    bool waitConnection(int seconds = 1);
+
+    /**
+     * Make a reconnect attempt. Called internally by Universe object.
+     */
+    bool reconnect();
+
+    bool isOutgoing() const;
+
+    /**
+     * Test if the connection is valid. This returns true in all conditions
+     * except where the socket has been disconnected permenantly, or was never
+     * able to connect, perhaps due to an invalid address, or is in middle of a
+     * reconnect attempt. (Valid states: kConnecting, kConnected)
+     * 
+     * Should return true only in cases when valid OS socket exists.
+     */
+    bool isValid() const;
+
+    /** node type */
+    virtual NodeType getType() const { return NodeType::kNode; }
+
+    NodeStatus status() const;
+    uint32_t getFTLVersion() const;
+    uint8_t getFTLMajor() const { return getFTLVersion() >> 16; }
+    uint8_t getFTLMinor() const { return (getFTLVersion() >> 8) & 0xFF; }
+    uint8_t getFTLPatch() const { return getFTLVersion() & 0xFF; }
+
+    /**
+     * Get the sockets protocol, address and port as a url string. This will be
+     * the same as the initial connection string on the client.
+     */
+    std::string getURI() const;
+
+    /**
+     * Get the UUID for this peer.
+     */
+    const ftl::UUID &id() const;
+
+    /**
+     * Get the peer id as a string.
+     */
+    std::string to_string() const;
+
+    void noReconnect();
+
+    unsigned int localID();
+
+    int connectionCount() const;
+
+ protected:
+    ftl::net::PeerPtr peer_;
 };
 
-}
-}
+}  // namespace protocol
+}  // namespace ftl
diff --git a/include/ftl/protocol/packet.hpp b/include/ftl/protocol/packet.hpp
index baaa97adacac140355b9de357a6ca6eadbf3a750..d75b79c318669e9078a2d426f914474b5a0eb65d 100644
--- a/include/ftl/protocol/packet.hpp
+++ b/include/ftl/protocol/packet.hpp
@@ -8,9 +8,9 @@
 
 #include <cstdint>
 #include <vector>
+#include <string>
 #include <ftl/protocol/codecs.hpp>
 #include <ftl/protocol/channels.hpp>
-//#include <msgpack.hpp>
 
 namespace ftl {
 namespace protocol {
@@ -23,15 +23,15 @@ static constexpr uint8_t kCurrentFTLVersion = 5;
  * First bytes of our file format.
  */
 struct Header {
-	const char magic[4] = {'F','T','L','F'};
-	uint8_t version = kCurrentFTLVersion;
+    const char magic[4] = {'F', 'T', 'L', 'F'};
+    uint8_t version = kCurrentFTLVersion;
 };
 
 /**
  * Version 2 header padding for potential indexing use.
  */
 struct IndexHeader {
-	int64_t reserved[8];
+    int64_t reserved[8];
 };
 
 /**
@@ -41,19 +41,17 @@ struct IndexHeader {
  * an empty wrapper around that. It is used in the encoding callback.
  */
 struct Packet {
-	ftl::protocol::Codec codec;
-	uint8_t reserved=0;
-	uint8_t frame_count=1;	// v4+ Frames included in this packet
+    ftl::protocol::Codec codec = ftl::protocol::Codec::kInvalid;
+    uint8_t reserved = 0;
+    uint8_t frame_count = 1;     // v4+ Frames included in this packet
 
-	uint8_t bitrate=0;		// v4+ For multi-bitrate encoding, 0=highest
+    uint8_t bitrate = 0;         // v4+ For multi-bitrate encoding, 0=highest
 
-	union {
-		uint8_t flags=0;			// Codec dependent flags (eg. I-Frame or P-Frame)
-		uint8_t packet_count;
-	};
-	std::vector<uint8_t> data;
-
-	//MSGPACK_DEFINE(codec, reserved, frame_count, bitrate, flags, data);
+    union {
+        uint8_t flags = 0;       // Codec dependent flags (eg. I-Frame or P-Frame)
+        uint8_t packet_count;
+    };
+    std::vector<uint8_t> data;
 };
 
 static constexpr unsigned int kStreamCap_Static = 0x01;
@@ -62,23 +60,21 @@ static constexpr unsigned int kStreamCap_NewConnection = 0x04;
 
 /** V4 packets have no stream flags field */
 struct StreamPacketV4 {
-	int version=4;			// FTL version, Not encoded into stream
-
-	int64_t timestamp;
-	uint8_t streamID;  		// Source number [or v4 frameset id]
-	uint8_t frame_number;	// v4+ First frame number (packet may include multiple frames)
-	ftl::protocol::Channel channel;		// Actual channel of this current set of packets
+    int version = 4;                   // FTL version, Not encoded into stream
 
-	inline int frameNumber() const { return (version >= 4) ? frame_number : streamID; }
-	inline size_t frameSetID() const { return (version >= 4) ? streamID : 0; }
+    int64_t timestamp;
+    uint8_t streamID;                  // Source number [or v4 frameset id]
+    uint8_t frame_number;              // v4+ First frame number (packet may include multiple frames)
+    ftl::protocol::Channel channel;    // Actual channel of this current set of packets
 
-	int64_t localTimestamp;  		// Not message packet / saved
-	unsigned int hint_capability;	// Is this a video stream, for example
-	size_t hint_source_total;		// Number of tracks per frame to expect
+    inline int frameNumber() const { return (version >= 4) ? frame_number : streamID; }
+    inline size_t frameSetID() const { return (version >= 4) ? streamID : 0; }
 
-	//MSGPACK_DEFINE(timestamp, streamID, frame_number, channel);
+    int64_t localTimestamp;            // Not message packet / saved
+    unsigned int hint_capability;      // Is this a video stream, for example
+    size_t hint_source_total;          // Number of tracks per frame to expect
 
-	operator std::string() const;
+    operator std::string() const;
 };
 
 /**
@@ -87,26 +83,24 @@ struct StreamPacketV4 {
  * or included before a frame packet structure.
  */
 struct StreamPacket {
-	int version = kCurrentFTLVersion;	// FTL version, Not encoded into stream
-
-	int64_t timestamp;
-	uint8_t streamID;  		// Source number [or v4 frameset id]
-	uint8_t frame_number;	// v4+ First frame number (packet may include multiple frames)
-	ftl::protocol::Channel channel;		// Actual channel of this current set of packets
-	uint8_t flags=0;
+    int version = kCurrentFTLVersion;    // FTL version, Not encoded into stream
 
-	inline int frameNumber() const { return (version >= 4) ? frame_number : streamID; }
-	inline size_t frameSetID() const { return (version >= 4) ? streamID : 0; }
+    int64_t timestamp;
+    uint8_t streamID;                    // Source number [or v4 frameset id]
+    uint8_t frame_number;                // v4+ First frame number (packet may include multiple frames)
+    ftl::protocol::Channel channel;      // Actual channel of this current set of packets
+    uint8_t flags = 0;
 
-	int64_t localTimestamp;  		// Not message packet / saved
-	unsigned int hint_capability;	// Is this a video stream, for example
-	size_t hint_source_total;		// Number of tracks per frame to expect
-	int retry_count = 0;			// Decode retry count
-	unsigned int hint_peerid=0;
+    inline int frameNumber() const { return (version >= 4) ? frame_number : streamID; }
+    inline size_t frameSetID() const { return (version >= 4) ? streamID : 0; }
 
-	//MSGPACK_DEFINE(timestamp, streamID, frame_number, channel, flags);
+    int64_t localTimestamp;              // Not message packet / saved
+    unsigned int hint_capability;        // Is this a video stream, for example
+    size_t hint_source_total;            // Number of tracks per frame to expect
+    int retry_count = 0;                 // Decode retry count
+    unsigned int hint_peerid = 0;
 
-	operator std::string() const;
+    operator std::string() const;
 };
 
 /**
@@ -114,9 +108,9 @@ struct StreamPacket {
  * saved or transmitted in a stream together.
  */
 struct PacketPair {
-	PacketPair(const StreamPacket &s, const Packet &p) : spkt(s), pkt(p) {}
-	const StreamPacket &spkt;
-	const Packet &pkt;
+    PacketPair(const StreamPacket &s, const Packet &p) : spkt(s), pkt(p) {}
+    const StreamPacket &spkt;
+    const Packet &pkt;
 };
 
 }  // namespace protocol
diff --git a/include/ftl/protocol/self.hpp b/include/ftl/protocol/self.hpp
index e21b5645b98a8e1711b8c1f5cc70783d8337cabd..765ccded80dfa57d8339f19a3a517613172c2f7a 100644
--- a/include/ftl/protocol/self.hpp
+++ b/include/ftl/protocol/self.hpp
@@ -1,19 +1,20 @@
 /**
- * @file node.hpp
+ * @file self.hpp
  * @copyright Copyright (c) 2022 University of Turku, MIT License
  * @author Nicolas Pope
  */
 
 #pragma once
 
+#include <memory>
+#include <string>
+#include <vector>
+#include <list>
 #include <ftl/uuid.hpp>
 #include <ftl/uri.hpp>
 #include <ftl/handle.hpp>
 #include <ftl/protocol/error.hpp>
 
-#include <memory>
-#include <string>
-
 namespace ftl {
 namespace net {
 class Universe;
@@ -24,63 +25,115 @@ namespace protocol {
 class Node;
 class Stream;
 
-class Self {	
-	public:
-	/** Peer for outgoing connection: resolve address and connect */
-	explicit Self(const std::shared_ptr<ftl::net::Universe> &impl);
-	virtual ~Self();
-
-	std::shared_ptr<ftl::protocol::Node> connectNode(const std::string &uri);
-
-	std::shared_ptr<ftl::protocol::Stream> createStream(const std::string &uri);
-
-	std::shared_ptr<ftl::protocol::Stream> getStream(const std::string &uri);
-	
-	void start();
-	
-	/**
-	 * Open a new listening port on a given interfaces.
-	 *   eg. "tcp://localhost:9000"
-	 * @param addr URI giving protocol, interface and port
-	 */
-	bool listen(const ftl::URI &addr);
-
-	std::vector<ftl::URI> getListeningURIs();
-
-	/**
-	 * Essential to call this before destroying anything that registered
-	 * callbacks or binds for RPC. It will terminate all connections and
-	 * stop any network activity but without deleting the net object.
-	 */
-	void shutdown();
-
-	bool isConnected(const ftl::URI &uri);
-	bool isConnected(const std::string &s);
-	
-	size_t numberOfNodes() const;
-
-	/**
-	 * Will block until all currently registered connnections have completed.
-	 * You should not use this, but rather use onConnect.
-	 */
-	int waitConnections(int seconds = 1);
-	
-	/** get peer pointer by peer UUID, returns nullptr if not found */
-	std::shared_ptr<ftl::protocol::Node> getNode(const ftl::UUID &pid) const;
-	/** get webservice peer pointer, returns nullptr if not connected to webservice */
-	std::shared_ptr<ftl::protocol::Node>  getWebService() const;
-	std::list<std::shared_ptr<ftl::protocol::Node>> getNodes() const;
-
-	ftl::Handle onConnect(const std::function<bool(const std::shared_ptr<ftl::protocol::Node>&)>&);
-	ftl::Handle onDisconnect(const std::function<bool(const std::shared_ptr<ftl::protocol::Node>&)>&);
-	ftl::Handle onError(const std::function<bool(const std::shared_ptr<ftl::protocol::Node>&, ftl::protocol::Error, const std::string & )>&);
-
-	// Used for testing
-	ftl::net::Universe *getUniverse() const { return universe_.get(); }
-
-	protected:
-	std::shared_ptr<ftl::net::Universe> universe_;
+/**
+ * @brief A wrapper providing RPC API and local node management. Internally the
+ * Self instance is responsible for handling all network operations. Typically
+ * there is just a single instance of this class, but more can be created for
+ * testing purposes.
+ * 
+ */
+class Self {
+ public:
+    /** Peer for outgoing connection: resolve address and connect */
+    explicit Self(const std::shared_ptr<ftl::net::Universe> &impl);
+    virtual ~Self();
+
+    /**
+     * @brief Connect to another host from this Self instance. Usually the
+     * namespace method can be used instead.
+     * 
+     * @param uri A TCP URI.
+     * @return std::shared_ptr<ftl::protocol::Node> 
+     */
+    std::shared_ptr<ftl::protocol::Node> connectNode(const std::string &uri);
+
+    /**
+     * @brief Create a new stream. Use the namespace method if possible.
+     * 
+     * @param uri A file:// or ftl:// URI.
+     * @return std::shared_ptr<ftl::protocol::Stream> 
+     */
+    std::shared_ptr<ftl::protocol::Stream> createStream(const std::string &uri);
+
+    /**
+     * @brief Open an existing stream. Use the namespace method if possible.
+     * 
+     * @param uri A file:// or ftl:// URI
+     * @return std::shared_ptr<ftl::protocol::Stream> 
+     */
+    std::shared_ptr<ftl::protocol::Stream> getStream(const std::string &uri);
+
+    void start();
+
+    /**
+     * Open a new listening port on a given interfaces.
+     *   eg. "tcp://localhost:9000"
+     * @param addr URI giving protocol, interface and port
+     */
+    bool listen(const ftl::URI &addr);
+
+    /**
+     * @brief Get the list of all listening addresses and ports.
+     * 
+     * @return std::vector<ftl::URI> 
+     */
+    std::vector<ftl::URI> getListeningURIs();
+
+    /**
+     * Essential to call this before destroying anything that registered
+     * callbacks or binds for RPC. It will terminate all connections and
+     * stop any network activity but without deleting the net object.
+     */
+    void shutdown();
+
+    bool isConnected(const ftl::URI &uri);
+    bool isConnected(const std::string &s);
+
+    size_t numberOfNodes() const;
+
+    /**
+     * Will block until all currently registered connnections have completed.
+     * You should not use this, but rather use onConnect.
+     */
+    int waitConnections(int seconds = 1);
+
+    /** get peer pointer by peer UUID, returns nullptr if not found */
+    std::shared_ptr<ftl::protocol::Node> getNode(const ftl::UUID &pid) const;
+    /** get webservice peer pointer, returns nullptr if not connected to webservice */
+    std::shared_ptr<ftl::protocol::Node>  getWebService() const;
+    std::list<std::shared_ptr<ftl::protocol::Node>> getNodes() const;
+
+    /**
+     * @brief Register a callback for new node connections.
+     * 
+     * @return ftl::Handle 
+     */
+    ftl::Handle onConnect(const std::function<bool(const std::shared_ptr<ftl::protocol::Node>&)>&);
+
+    /**
+     * @brief Register a callback for node disconnects.
+     * 
+     * @return ftl::Handle 
+     */
+    ftl::Handle onDisconnect(const std::function<bool(const std::shared_ptr<ftl::protocol::Node>&)>&);
+
+    /**
+     * @brief Register a callback for any node or network errors. Note that the node pointer can
+     * be null if the error was not associated with a specific node.
+     * 
+     * @return ftl::Handle 
+     */
+    ftl::Handle onError(
+        const std::function<bool(const std::shared_ptr<ftl::protocol::Node>&,
+        ftl::protocol::Error,
+        const std::string &)>&);
+
+    // Used for testing
+    ftl::net::Universe *getUniverse() const { return universe_.get(); }
+
+ protected:
+    std::shared_ptr<ftl::net::Universe> universe_;
 };
 
-}
-}
+}  // namespace protocol
+}  // namespace ftl
diff --git a/include/ftl/protocol/streams.hpp b/include/ftl/protocol/streams.hpp
index 1ca85e88da5d11fb1682813b83474823e602de9e..2e298debb28015f06f0934cbf12b23cd9d6019bc 100644
--- a/include/ftl/protocol/streams.hpp
+++ b/include/ftl/protocol/streams.hpp
@@ -6,6 +6,12 @@
 
 #pragma once
 
+#include <string>
+#include <vector>
+#include <unordered_set>
+#include <any>
+#include <unordered_map>
+#include <memory>
 #include <ftl/handle.hpp>
 #include <ftl/threads.hpp>
 #include <ftl/protocol/channels.hpp>
@@ -13,51 +19,52 @@
 #include <ftl/protocol/packet.hpp>
 #include <ftl/protocol/frameid.hpp>
 #include <ftl/protocol/error.hpp>
-#include <string>
-#include <vector>
-#include <unordered_set>
-#include <any>
 
 namespace ftl {
 namespace protocol {
-/* Represents a request for data through a stream */
+/** Represents a request for data through a stream */
 struct Request {
-	FrameID id;
-	ftl::protocol::Channel channel;
-	int bitrate;
-	int count;
-	ftl::protocol::Codec codec;
+    FrameID id;
+    ftl::protocol::Channel channel;
+    int bitrate;
+    int count;
+    ftl::protocol::Codec codec;
 };
 
 using RequestCallback = std::function<bool(const ftl::protocol::Request&)>;
 
 using StreamCallback = std::function<bool(const ftl::protocol::StreamPacket &, const ftl::protocol::Packet &)>;
 
+/**
+ * @brief Enumeration of possible stream properties. Not all properties are supported
+ * by all stream types, but they allow additional control and data access.
+ * 
+ */
 enum struct StreamProperty {
     kInvalid = 0,
     kLooping,
     kSpeed,
     kBitrate,
-	kMaxBitrate,
+    kMaxBitrate,
     kAdaptiveBitrate,
-	kObservers,
-	kURI,
-	kPaused,
-	kBytesSent,
-	kBytesReceived,
-	kLatency,
-	kFrameRate,
-	kName,
-	kDescription,
-	kTags,
-	kUser
+    kObservers,
+    kURI,
+    kPaused,
+    kBytesSent,
+    kBytesReceived,
+    kLatency,
+    kFrameRate,
+    kName,
+    kDescription,
+    kTags,
+    kUser
 };
 
 enum struct StreamType {
-    kMixed,
+    kMixed,     // Multiple types of stream
     kUnknown,
-    kLive,
-    kRecorded
+    kLive,      // Net stream
+    kRecorded   // File stream
 };
 
 /**
@@ -68,158 +75,271 @@ enum struct StreamType {
  * Streams are bidirectional, frames can be both received and written.
  */
 class Stream {
-	public:
-	virtual ~Stream() {};
-
-	virtual std::string name() const;
-
-	/**
-	 * Obtain all packets for next frame. The provided callback function is
-	 * called once for every packet. This function might continue to call the
-	 * callback even after the read function returns, for example with a
-	 * NetStream.
-	 */
-	ftl::Handle onPacket(const StreamCallback &cb) { return cb_.on(cb); }
-
-	ftl::Handle onRequest(const std::function<bool(const Request &)> &cb) { return request_cb_.on(cb); }
-
-	virtual bool post(const ftl::protocol::StreamPacket &, const ftl::protocol::Packet &)=0;
-
-    // TODO: Add methods for: pause, paused, statistics
-
-	/**
-	 * Start the stream. Calls to the onPacket callback will only occur after
-	 * a call to this function (and before a call to end()).
-	 */
-	virtual bool begin()=0;
-
-	virtual bool end()=0;
-
-	/**
-	 * Is the stream active? Generally true if begin() has been called, false
-	 * initially and after end(). However, it may go false for other reasons.
-	 * If false, no calls to onPacket will occur and posts will be ignored.
-	 */
-	virtual bool active()=0;
-
-	/**
-	 * @brief Clear all state. This will remove all information about available
-	 * and enabled frames or channels. You will then need to enable frames and
-	 * channels again. If active the stream will remain active.
-	 * 
-	 */
-	virtual void reset();
-
-	/**
-	 * @brief Re-request all channels and state. This will also cause video encoding
-	 * to generate new I-frames as if a new connection is made. All persistent data
-	 * channels would also become available. For file streams this would reset the
-	 * stream to the beginning of the file.
-	 * 
-	 */
-	virtual void refresh();
-
-	/**
-	 * @brief Check if a frame is available.
-	 * 
-	 * @param id Frameset and frame number
-	 * @return true if data is available for the frame
-	 * @return false if no data has been seen
-	 */
-	bool available(FrameID id) const;
-
-	bool available(FrameID id, ftl::protocol::Channel channel) const;
-
-	bool available(FrameID id, const ftl::protocol::ChannelSet channels) const;
-
-	ftl::Handle onAvailable(const std::function<bool(FrameID, ftl::protocol::Channel)> &cb) { return avail_cb_.on(cb); }
-
-	/**
-	 * @brief Get all channels seen for a frame. If the frame does not exist then
-	 * an empty set is returned.
-	 * 
-	 * @param id Frameset and frame number
-	 * @return Set of all seen channels, or empty. 
-	 */
-	ftl::protocol::ChannelSet channels(FrameID id) const;
-
-	ftl::protocol::ChannelSet enabledChannels(FrameID id) const;
-
-	/**
-	 * @brief Get all available frames in the stream.
-	 * 
-	 * @return Set of frame IDs
-	 */
-	std::unordered_set<FrameID> frames() const;
-
-	/**
-	 * @brief Get all enabled frames in the stream.
-	 * 
-	 * @return Set of frame IDs
-	 */
-	std::unordered_set<FrameID> enabled() const;
-
-	/**
-	 * @brief Check if a frame is enabled.
-	 * 
-	 * @param id Frameset and frame number
-	 * @return true if data for this frame is enabled.
-	 * @return false if data not enabled or frame does not exist.
-	 */
-	bool enabled(FrameID id) const;
-
-	bool enabled(FrameID id, ftl::protocol::Channel channel) const;
-
-	/**
-	 * Number of framesets in stream.
-	 */
-	inline size_t size() const { return state_.size(); }
-
-	virtual bool enable(FrameID id);
-
-	virtual bool enable(FrameID id, ftl::protocol::Channel channel);
-
-	virtual bool enable(FrameID id, const ftl::protocol::ChannelSet &channels);
-
-	// TODO: Disable
-
-	virtual void setProperty(ftl::protocol::StreamProperty opt, std::any value)=0;
-
-	virtual std::any getProperty(ftl::protocol::StreamProperty opt)=0;
-
-	virtual bool supportsProperty(ftl::protocol::StreamProperty opt)=0;
-
-	virtual StreamType type() const { return StreamType::kUnknown; }
-
-	ftl::Handle onError(const std::function<bool(ftl::protocol::Error, const std::string &)> &cb) { return error_cb_.on(cb); }
-
-	protected:
-	void trigger(const ftl::protocol::StreamPacket &spkt, const ftl::protocol::Packet &pkt);
-
-	void seen(FrameID id, ftl::protocol::Channel channel);
-
-	void request(const Request &req);
-
-	void error(ftl::protocol::Error, const std::string &str);
-
-	mutable SHARED_MUTEX mtx_;
-
-	private:
-	struct FSState {
-		bool enabled = false;
-		ftl::protocol::ChannelSet selected;
-		ftl::protocol::ChannelSet available;
-		// TODO: Add a name and metadata
-	};
-
-	ftl::Handler<const ftl::protocol::StreamPacket&, const ftl::protocol::Packet&> cb_;
-	ftl::Handler<const Request &> request_cb_;
-	ftl::Handler<FrameID, ftl::protocol::Channel> avail_cb_;
-	ftl::Handler<ftl::protocol::Error, const std::string&> error_cb_;
-	std::unordered_map<int, FSState> state_;
+ public:
+    virtual ~Stream() {}
+
+    virtual std::string name() const;
+
+    /**
+     * Obtain all packets for next frame. The provided callback function is
+     * called once for every packet. This function might continue to call the
+     * callback even after the read function returns, for example with a
+     * NetStream.
+     */
+    ftl::Handle onPacket(const StreamCallback &cb) { return cb_.on(cb); }
+
+    /**
+     * @brief Register a callback for frame and channel requests. Remote machines can send
+     * requests, at which point the data should be generated and sent properly.
+     * 
+     * @param cb 
+     * @return ftl::Handle 
+     */
+    ftl::Handle onRequest(const std::function<bool(const Request &)> &cb) { return request_cb_.on(cb); }
+
+    /**
+     * @brief Send packets, either to file or over the network. Packets should follow
+     * the overall protocol rules, detailed elsewhere.
+     * 
+     * @return true if sent
+     * @return false if dropped
+     */
+    virtual bool post(const ftl::protocol::StreamPacket &, const ftl::protocol::Packet &) = 0;
+
+    // TODO(Nick): Add methods for: pause, paused, statistics
+
+    /**
+     * Start the stream. Calls to the onPacket callback will only occur after
+     * a call to this function (and before a call to end()).
+     */
+    virtual bool begin() = 0;
+
+    virtual bool end() = 0;
+
+    /**
+     * Is the stream active? Generally true if begin() has been called, false
+     * initially and after end(). However, it may go false for other reasons.
+     * If false, no calls to onPacket will occur and posts will be ignored.
+     */
+    virtual bool active() = 0;
+
+    /**
+     * @brief Clear all state. This will remove all information about available
+     * and enabled frames or channels. You will then need to enable frames and
+     * channels again. If active the stream will remain active.
+     * 
+     */
+    virtual void reset();
+
+    /**
+     * @brief Re-request all channels and state. This will also cause video encoding
+     * to generate new I-frames as if a new connection is made. All persistent data
+     * channels would also become available. For file streams this would reset the
+     * stream to the beginning of the file.
+     * 
+     */
+    virtual void refresh();
+
+    /**
+     * @brief Check if a frame is available.
+     * 
+     * @param id Frameset and frame number
+     * @return true if data is available for the frame
+     * @return false if no data has been seen
+     */
+    bool available(FrameID id) const;
+
+    /**
+     * @brief Check if a channel for a frame is available.
+     * 
+     * @param id Frameset and frame number
+     * @param channel 
+     * @return true if there is channel data
+     * @return false if the channel does not exist
+     */
+    bool available(FrameID id, ftl::protocol::Channel channel) const;
+
+    /**
+     * @brief Check if all channels in a set are available.
+     * 
+     * @param id Frameset and frame number
+     * @param channels Set of channels to check
+     * @return true if all channels exist
+     * @return false if one or more do not exist
+     */
+    bool available(FrameID id, const ftl::protocol::ChannelSet channels) const;
+
+    /**
+     * @brief Register a callback for when new frames and channels become available.
+     * 
+     * @param cb 
+     * @return ftl::Handle 
+     */
+    ftl::Handle onAvailable(const std::function<bool(FrameID, ftl::protocol::Channel)> &cb) { return avail_cb_.on(cb); }
+
+    /**
+     * @brief Get all channels seen for a frame. If the frame does not exist then
+     * an empty set is returned.
+     * 
+     * @param id Frameset and frame number
+     * @return Set of all seen channels, or empty. 
+     */
+    ftl::protocol::ChannelSet channels(FrameID id) const;
+
+    /**
+     * @brief Obtain a set of all active channels for a frame.
+     * 
+     * @param id Frameset and frame number
+     * @return ftl::protocol::ChannelSet 
+     */
+    ftl::protocol::ChannelSet enabledChannels(FrameID id) const;
+
+    /**
+     * @brief Get all available frames in the stream.
+     * 
+     * @return Set of frame IDs
+     */
+    std::unordered_set<FrameID> frames() const;
+
+    /**
+     * @brief Get all enabled frames in the stream.
+     * 
+     * @return Set of frame IDs
+     */
+    std::unordered_set<FrameID> enabled() const;
+
+    /**
+     * @brief Check if a frame is enabled.
+     * 
+     * @param id Frameset and frame number
+     * @return true if data for this frame is enabled.
+     * @return false if data not enabled or frame does not exist.
+     */
+    bool enabled(FrameID id) const;
+
+    /**
+     * @brief Check if a specific channel is enabled for a frame.
+     * 
+     * @param id Frameset and frame number
+     * @param channel 
+     * @return true if the channel is active
+     * @return false if the channel is not active or does not exist
+     */
+    bool enabled(FrameID id, ftl::protocol::Channel channel) const;
+
+    /**
+     * Number of framesets in stream.
+     */
+    inline size_t size() const { return state_.size(); }
+
+    /**
+     * @brief Activate a frame. This allows availability information to be gathered
+     * for the frame which might not otherwise be available. However, data is likely
+     * missing unless a channel is enabled.
+     * 
+     * @param id Frameset and frame number
+     * @return true if the frame could be enabled
+     * @return false if the frame could not be found or enabled
+     */
+    virtual bool enable(FrameID id);
+
+    /**
+     * @brief Request a specific channel in a frame. Once the request is made data
+     * should become available if it exists. This will also enable the frame if
+     * not already enabled.
+     * 
+     * @param id Frameset and frame number
+     * @param channel 
+     * @return true if the channel is available and enabled
+     * @return false if the channel does not exist
+     */
+    virtual bool enable(FrameID id, ftl::protocol::Channel channel);
+
+    /**
+     * @brief Activate a set of channels for a frame. Requests for data for each
+     * given channel are sent and the data should then become available.
+     * 
+     * @param id Frameset and frame number
+     * @param channels a set of all channels to activate
+     * @return true if all channels could be enabled
+     * @return false if some channel could not be enabled
+     */
+    virtual bool enable(FrameID id, const ftl::protocol::ChannelSet &channels);
+
+    // TODO(Nick): Disable
+
+    /**
+     * @brief Set a stream property to a new value. If the property is not supported,
+     * is readonly or an invalid value type is given, then an exception is thrown.
+     * Check if the property is supported first.
+     * 
+     * @param opt 
+     * @param value 
+     */
+    virtual void setProperty(ftl::protocol::StreamProperty opt, std::any value) = 0;
+
+    /**
+     * @brief Get the value of a stream property. If the property is not supported then
+     * an exception is thrown. The result is an `any` object that should be casted
+     * correctly by the user.
+     * 
+     * @param opt 
+     * @return std::any 
+     */
+    virtual std::any getProperty(ftl::protocol::StreamProperty opt) = 0;
+
+    /**
+     * @brief Check if a property is supported. No exceptions are thrown.
+     * 
+     * @param opt 
+     * @return true if the property is at least readable
+     * @return false if the property is unsupported
+     */
+    virtual bool supportsProperty(ftl::protocol::StreamProperty opt) = 0;
+
+    virtual StreamType type() const { return StreamType::kUnknown; }
+
+    /**
+     * @brief Register a callback for asynchronous stream errors.
+     * 
+     * @param cb 
+     * @return ftl::Handle 
+     */
+    ftl::Handle onError(const std::function<bool(ftl::protocol::Error, const std::string &)> &cb) {
+        return error_cb_.on(cb);
+    }
+
+ protected:
+    /** Dispatch packets to callbacks */
+    void trigger(const ftl::protocol::StreamPacket &spkt, const ftl::protocol::Packet &pkt);
+
+    /** Mark the channel and frame as available */
+    void seen(FrameID id, ftl::protocol::Channel channel);
+
+    /** Dispatch a request */
+    void request(const Request &req);
+
+    /** Report a stream error */
+    void error(ftl::protocol::Error, const std::string &str);
+
+    mutable SHARED_MUTEX mtx_;
+
+ private:
+    struct FSState {
+        bool enabled = false;
+        ftl::protocol::ChannelSet selected;
+        ftl::protocol::ChannelSet available;
+        // TODO(Nick): Add a name and metadata
+    };
+
+    ftl::Handler<const ftl::protocol::StreamPacket&, const ftl::protocol::Packet&> cb_;
+    ftl::Handler<const Request &> request_cb_;
+    ftl::Handler<FrameID, ftl::protocol::Channel> avail_cb_;
+    ftl::Handler<ftl::protocol::Error, const std::string&> error_cb_;
+    std::unordered_map<int, FSState> state_;
 };
 
 using StreamPtr = std::shared_ptr<Stream>;
 
-}
-}
+}  // namespace protocol
+}  // namespace ftl
diff --git a/include/ftl/threads.hpp b/include/ftl/threads.hpp
index 955a54da0d7385642a1dc3de7ab9379692b31439..0d62a76ab0d616dfdb060da269121f64cf032203 100644
--- a/include/ftl/threads.hpp
+++ b/include/ftl/threads.hpp
@@ -24,47 +24,47 @@
 #define RECURSIVE_MUTEX std::recursive_timed_mutex
 #define SHARED_MUTEX std::shared_timed_mutex
 
-#define UNIQUE_LOCK(M,L) std::unique_lock<std::remove_reference<decltype(M)>::type> L(M, std::chrono::milliseconds(MUTEX_TIMEOUT)); while (!L) { LOG(ERROR) << "Mutex timeout"; L.try_lock_for(std::chrono::milliseconds(MUTEX_TIMEOUT)); };
-#define SHARED_LOCK(M,L) std::shared_lock<std::remove_reference<decltype(M)>::type> L(M, std::chrono::milliseconds(MUTEX_TIMEOUT)); while (!L) { LOG(ERROR) << "Mutex timeout"; L.try_lock_for(std::chrono::milliseconds(MUTEX_TIMEOUT)); };
+#define UNIQUE_LOCK(M, L) std::unique_lock<std::remove_reference<decltype(M)>::type> L(M, std::chrono::milliseconds(MUTEX_TIMEOUT)); while (!L) { LOG(ERROR) << "Mutex timeout"; L.try_lock_for(std::chrono::milliseconds(MUTEX_TIMEOUT)); };
+#define SHARED_LOCK(M, L) std::shared_lock<std::remove_reference<decltype(M)>::type> L(M, std::chrono::milliseconds(MUTEX_TIMEOUT)); while (!L) { LOG(ERROR) << "Mutex timeout"; L.try_lock_for(std::chrono::milliseconds(MUTEX_TIMEOUT)); };
 
 #else
 #define MUTEX std::mutex
 #define RECURSIVE_MUTEX std::recursive_mutex
 #define SHARED_MUTEX std::shared_mutex
 
-#define UNIQUE_LOCK(M,L) std::unique_lock<std::remove_reference<decltype(M)>::type> L(M);
-#define SHARED_LOCK(M,L) std::shared_lock<std::remove_reference<decltype(M)>::type> L(M);
+#define UNIQUE_LOCK(M, L) std::unique_lock<std::remove_reference<decltype(M)>::type> L(M);
+#define SHARED_LOCK(M, L) std::shared_lock<std::remove_reference<decltype(M)>::type> L(M);
 #endif  // DEBUG_MUTEX
 
 #define SHARED_LOCK_TYPE(M) std::shared_lock<M>
 
 namespace ftl {
-	extern ctpl::thread_pool pool;
+    extern ctpl::thread_pool pool;
 
 namespace threads {
 
 /** Upgrade shared lock to exclusive lock and re-acquire shared lock at end of 
  * scope. */
 class _write_lock {
-public:
-	explicit _write_lock(std::shared_mutex& mtx) : mtx_(&mtx) {
-		mtx_->unlock_shared();
-		mtx_->lock();
-	}
-
-	~_write_lock() {
-		mtx_->unlock();
-		mtx_->lock_shared();
-	}
-
-private:
-	std::shared_mutex* const mtx_;
+ public:
+    explicit _write_lock(std::shared_mutex& mtx) : mtx_(&mtx) {
+        mtx_->unlock_shared();
+        mtx_->lock();
+    }
+
+    ~_write_lock() {
+        mtx_->unlock();
+        mtx_->lock_shared();
+    }
+
+ private:
+    std::shared_mutex* const mtx_;
 };
 
 /** Upgrade already acquired SHARED_LOCK to exclusive lock and re-acquire shared
  * lock at end of scope. Shared lock must be already acquired on mutex! If more
  * careful locking is required, use std::..._lock directly */
-#define WRITE_LOCK(M,L) ftl::threads::_write_lock L(M);
+#define WRITE_LOCK(M, L) ftl::threads::_write_lock L(M);
 
-}
-}
+}  // namespace threads
+}  // namespace ftl
diff --git a/include/ftl/time.hpp b/include/ftl/time.hpp
index 338b63c49e5d8cb5f9268c2f69dae226e51ce230..dc8ded925f59e04d6583595463610ae9d0fe4dda 100644
--- a/include/ftl/time.hpp
+++ b/include/ftl/time.hpp
@@ -1,3 +1,9 @@
+/**
+ * @file time.hpp
+ * @copyright Copyright (c) 2020 University of Turku, MIT License
+ * @author Nicolas Pope
+ */
+
 #pragma once
 
 #include <cinttypes>
@@ -20,5 +26,5 @@ double get_time_seconds();
  */
 void setClockAdjustment(int64_t ms);
 
-}
-}
+}  // namespace time
+}  // namespace ftl
diff --git a/include/ftl/uri.hpp b/include/ftl/uri.hpp
index 4d8b7e7bc763be957cd8ddc0eb4066180476bfa5..c1b8abe87c1bc441a36e4190bf27f4cbc09fc6ae 100644
--- a/include/ftl/uri.hpp
+++ b/include/ftl/uri.hpp
@@ -6,109 +6,110 @@
 
 #pragma once
 
-#include <nlohmann/json_fwd.hpp>
 #include <uriparser/Uri.h>
 #include <string>
 #include <vector>
 #include <map>
+#include <nlohmann/json_fwd.hpp>
+
 
 namespace ftl {
 
-	typedef const char * uri_t;
-
-	/**
-	 * Universal Resource Identifier. Parse, modify, represent and generate URIs.
-	 */
-	class URI {
-		public:
-		URI(): m_valid(false) {}
-		explicit URI(uri_t puri);
-		explicit URI(const std::string &puri);
-		explicit URI(const URI &c);
-
-		~URI() {};
-
-		enum scheme_t : int {
-			SCHEME_NONE,
-			SCHEME_TCP,
-			SCHEME_UDP,
-			SCHEME_FTL,		// Future Tech Lab
-			SCHEME_HTTP,
-			SCHEME_WS,
-			SCHEME_WSS,
-			SCHEME_IPC,
-			SCHEME_FILE,
-			SCHEME_OTHER,
-			SCHEME_DEVICE,
-			SCHEME_GROUP
-		};
-
-		bool isValid() const { return m_valid; };
-		const std::string &getHost() const { return m_host; };
-		int getPort() const { return m_port; };
-		scheme_t getProtocol() const { return m_proto; };
-		scheme_t getScheme() const { return m_proto; };
-		const std::string &getPath() const { return m_path; };
-		const std::string &getFragment() const { return m_frag; }
-		std::string getQuery() const;
-		const std::string &getBaseURI() const { return m_base; };
-		bool hasUserInfo() const;
-		const std::string &getUserInfo() const; 
-
-		/**
-		 * Get the URI without query parameters, and limit path to length N.
-		 * If N is negative then it is taken from full path length.
-		 */
-		std::string getBaseURI(int n) const;
-
-		std::string getBaseURIWithUser() const;
-
-		std::string getPathSegment(int n) const;
-
-		inline size_t getPathLength() const { return m_pathseg.size(); }
-
-		void setAttribute(const std::string &key, const std::string &value);
-		void setAttribute(const std::string &key, int value);
-
-		template <typename T>
-		T getAttribute(const std::string &key) const {
-			auto i = m_qmap.find(key);
-			return (i != m_qmap.end()) ? T(i->second) : T();
-		}
-
-		bool hasAttribute(const std::string &a) const { return m_qmap.count(a) > 0; }
-
-		std::string to_string() const;
-
-		void to_json(nlohmann::json &) const;
-
-		private:
-		void _parse(uri_t puri);
-
-		private:
-		bool m_valid;
-		std::string m_host;
-		std::string m_path;
-		std::string m_frag;
-		std::string m_base;
-		std::string m_userinfo;
-		std::vector<std::string> m_pathseg;
-		int m_port = 0;
-		scheme_t m_proto = scheme_t::SCHEME_NONE;
-		std::string m_protostr;
-		// std::string m_query;
-		std::map<std::string, std::string> m_qmap;
-	};
-
-	template <>
-	inline int URI::getAttribute<int>(const std::string &key) const {
-		auto i = m_qmap.find(key);
-		return (i != m_qmap.end()) ? std::stoi(i->second) : 0;
-	}
-
-	template <>
-	inline std::string URI::getAttribute<std::string>(const std::string &key) const {
-		auto i = m_qmap.find(key);
-		return (i != m_qmap.end()) ? i->second : "";
-	}
+typedef const char * uri_t;
+
+/**
+ * Universal Resource Identifier. Parse, modify, represent and generate URIs.
+ */
+class URI {
+ public:
+    URI(): m_valid(false) {}
+    explicit URI(uri_t puri);
+    explicit URI(const std::string &puri);
+    explicit URI(const URI &c);
+
+    ~URI() {};
+
+    enum scheme_t : int {
+        SCHEME_NONE,
+        SCHEME_TCP,
+        SCHEME_UDP,
+        SCHEME_FTL,      // Future Tech Lab
+        SCHEME_HTTP,
+        SCHEME_WS,
+        SCHEME_WSS,
+        SCHEME_IPC,
+        SCHEME_FILE,
+        SCHEME_OTHER,
+        SCHEME_DEVICE,
+        SCHEME_GROUP
+    };
+
+    bool isValid() const { return m_valid; }
+    const std::string &getHost() const { return m_host; }
+    int getPort() const { return m_port; }
+    scheme_t getProtocol() const { return m_proto; }
+    scheme_t getScheme() const { return m_proto; }
+    const std::string &getPath() const { return m_path; }
+    const std::string &getFragment() const { return m_frag; }
+    std::string getQuery() const;
+    const std::string &getBaseURI() const { return m_base; }
+    bool hasUserInfo() const;
+    const std::string &getUserInfo() const;
+
+    /**
+     * Get the URI without query parameters, and limit path to length N.
+     * If N is negative then it is taken from full path length.
+     */
+    std::string getBaseURI(int n) const;
+
+    std::string getBaseURIWithUser() const;
+
+    std::string getPathSegment(int n) const;
+
+    inline size_t getPathLength() const { return m_pathseg.size(); }
+
+    void setAttribute(const std::string &key, const std::string &value);
+    void setAttribute(const std::string &key, int value);
+
+    template <typename T>
+    T getAttribute(const std::string &key) const {
+        auto i = m_qmap.find(key);
+        return (i != m_qmap.end()) ? T(i->second) : T();
+    }
+
+    bool hasAttribute(const std::string &a) const { return m_qmap.count(a) > 0; }
+
+    std::string to_string() const;
+
+    void to_json(nlohmann::json &) const;
+
+ private:
+    void _parse(uri_t puri);
+
+    bool m_valid;
+    std::string m_host;
+    std::string m_path;
+    std::string m_frag;
+    std::string m_base;
+    std::string m_userinfo;
+    std::vector<std::string> m_pathseg;
+    int m_port = 0;
+    scheme_t m_proto = scheme_t::SCHEME_NONE;
+    std::string m_protostr;
+    // std::string m_query;
+    std::map<std::string, std::string> m_qmap;
+};
+
+template <>
+inline int URI::getAttribute<int>(const std::string &key) const {
+    auto i = m_qmap.find(key);
+    return (i != m_qmap.end()) ? std::stoi(i->second) : 0;
+}
+
+template <>
+inline std::string URI::getAttribute<std::string>(const std::string &key) const {
+    auto i = m_qmap.find(key);
+    return (i != m_qmap.end()) ? i->second : "";
 }
+
+}  // namespace ftl
diff --git a/include/ftl/utility/base64.hpp b/include/ftl/utility/base64.hpp
index 197bd7df333629c5e8316fd36a7e654977ecd30f..cc1c4aea845877aff2e63b590398e0ede4507398 100644
--- a/include/ftl/utility/base64.hpp
+++ b/include/ftl/utility/base64.hpp
@@ -3,8 +3,7 @@
 //  Version: 2.rc.04 (release candidate)
 //
 
-#ifndef BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A
-#define BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A
+#pragma once
 
 #include <string>
 
@@ -12,8 +11,8 @@
 #include <string_view>
 #endif  // __cplusplus >= 201703L
 
-std::string base64_encode     (std::string const& s, bool url = false);
-std::string base64_encode_pem (std::string const& s);
+std::string base64_encode(std::string const& s, bool url = false);
+std::string base64_encode_pem(std::string const& s);
 std::string base64_encode_mime(std::string const& s);
 
 std::string base64_decode(std::string const& s, bool remove_linebreaks = false);
@@ -25,11 +24,9 @@ std::string base64_encode(unsigned char const*, size_t len, bool url = false);
 // Requires C++17
 // Provided by Yannic Bonenberger (https://github.com/Yannic)
 //
-std::string base64_encode     (std::string_view s, bool url = false);
-std::string base64_encode_pem (std::string_view s);
+std::string base64_encode(std::string_view s, bool url = false);
+std::string base64_encode_pem(std::string_view s);
 std::string base64_encode_mime(std::string_view s);
 
 std::string base64_decode(std::string_view s, bool remove_linebreaks = false);
 #endif  // __cplusplus >= 201703L
-
-#endif /* BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A */
diff --git a/include/ftl/uuid.hpp b/include/ftl/uuid.hpp
index 875a698c98a9e725c397e3f53d1b2d8211c4bcc3..cb6e75c29b1b60587245ebbd1786018ed68f1d91 100644
--- a/include/ftl/uuid.hpp
+++ b/include/ftl/uuid.hpp
@@ -22,130 +22,131 @@
 #include <msgpack.hpp>
 
 namespace ftl {
-	/**
-	 * C++ Wrapper for libuuid. The default constructor generates a new UUID.
-	 */
-	class UUID {
-		public:
-		UUID() {
+    /**
+     * C++ Wrapper for libuuid. The default constructor generates a new UUID.
+     */
+class UUID {
+ public:
+    UUID() {
 #ifdef WIN32
-			::UuidCreate(&guid_);
+        ::UuidCreate(&guid_);
 #else
-			uuid_generate(uuid_);
+        uuid_generate(uuid_);
 #endif
-		}
-		explicit UUID(int u) { memset(uuid_,u,16); }
-		UUID(const ftl::UUID &u) { memcpy(uuid_,u.uuid_,16); }
-		explicit UUID(const unsigned char *raw) { memcpy(uuid_, raw, 16); }
-		explicit UUID(const std::string &s) {
+    }
+    explicit UUID(int u) { memset(uuid_, u, 16); }
+    explicit UUID(const ftl::UUID &u) { memcpy(uuid_, u.uuid_, 16); }
+    explicit UUID(const unsigned char *raw) { memcpy(uuid_, raw, 16); }
+    explicit UUID(const std::string &s) {
 #ifdef WIN32
-			// TODO(Nick) Windows UUID parse
-			LOG(ERROR) << "TODO: parse UUID from string (Windows)";
+        // TODO(Nick) Windows UUID parse
+        LOG(ERROR) << "TODO: parse UUID from string (Windows)";
 #else
-			if (uuid_parse(s.c_str(), uuid_) < 0) {
-				memset(uuid_,0,16);
-			}
+        if (uuid_parse(s.c_str(), uuid_) < 0) {
+            memset(uuid_, 0, 16);
+        }
 #endif
-		}
-		
-		UUID &operator=(const UUID &u)  {
-			memcpy(&uuid_,&u.uuid_,16); return *this;
-		}
-		bool operator==(const UUID &u) const {
-			return memcmp(&uuid_,&u.uuid_,16) == 0;
-		}
-		bool operator!=(const UUID &u) const {
-			return memcmp(&uuid_,&u.uuid_,16) != 0;
-		}
-		bool operator<(const UUID &u) const {
-			return strncmp((const char*)uuid_, (const char *)u.uuid_, 16) < 0;
-		}
-		
-		/// returns false if all bytes zero, otherwise returns true
-		bool is_valid() {
-			bool all_zeros = true;
-			for (int i = 0; i < 16; i++) { all_zeros &= (0u == uuid_[i]); }
-			return !all_zeros;
-		}
+    }
 
-		/**
-		 * Get a raw data string.
-		 */
-		std::string str() const { return std::string((char*)&uuid_,16); }
-		const unsigned char *raw() const { return (const unsigned char*)&uuid_; }
-		
-		/**
-		 * Get a pretty string.
-		 */
-		std::string to_string() const {
-			static const char *digits = "0123456789abcdef";
-			std::string rc(sizeof(uuid_)*2+4,'0');
+    UUID &operator=(const UUID &u)  {
+        memcpy(&uuid_, &u.uuid_, 16);
+        return *this;
+    }
+    bool operator==(const UUID &u) const {
+        return memcmp(&uuid_, &u.uuid_, 16) == 0;
+    }
+    bool operator!=(const UUID &u) const {
+        return memcmp(&uuid_, &u.uuid_, 16) != 0;
+    }
+    bool operator<(const UUID &u) const {
+        return strncmp((const char*)uuid_, (const char *)u.uuid_, 16) < 0;
+    }
 
-			size_t j=0;
-			for (size_t i=0 ; i<4; ++i) {
-				rc[j+1] = digits[uuid_[i] & 0x0f];
-				rc[j] = digits[(uuid_[i] >> 4) & 0x0f];
-				j+=2;
-			}
-			rc[j++] = '-';
-			for (size_t i=4 ; i<6; ++i) {
-				rc[j+1] = digits[uuid_[i] & 0x0f];
-				rc[j] = digits[(uuid_[i] >> 4) & 0x0f];
-				j+=2;
-			}
-			rc[j++] = '-';
-			for (size_t i=6 ; i<8; ++i) {
-				rc[j+1] = digits[uuid_[i] & 0x0f];
-				rc[j] = digits[(uuid_[i] >> 4) & 0x0f];
-				j+=2;
-			}
-			rc[j++] = '-';
-			for (size_t i=8 ; i<10; ++i) {
-				rc[j+1] = digits[uuid_[i] & 0x0f];
-				rc[j] = digits[(uuid_[i] >> 4) & 0x0f];
-				j+=2;
-			}
-			rc[j++] = '-';
-			for (size_t i=10 ; i<16; ++i) {
-				rc[j+1] = digits[uuid_[i] & 0x0f];
-				rc[j] = digits[(uuid_[i] >> 4) & 0x0f];
-				j+=2;
-			}
-			return rc;
+    /// returns false if all bytes zero, otherwise returns true
+    bool is_valid() {
+        bool all_zeros = true;
+        for (int i = 0; i < 16; i++) { all_zeros &= (0u == uuid_[i]); }
+        return !all_zeros;
+    }
+
+    /**
+     * Get a raw data string.
+     */
+    std::string str() const { return std::string(reinterpret_cast<const char*>(&uuid_), 16); }
+    const unsigned char *raw() const { return (const unsigned char*)&uuid_; }
+
+    /**
+     * Get a pretty string.
+     */
+    std::string to_string() const {
+        static const char *digits = "0123456789abcdef";
+        std::string rc(sizeof(uuid_)*2+4, '0');
+
+        size_t j = 0;
+        for (size_t i = 0 ; i < 4; ++i) {
+            rc[j+1] = digits[uuid_[i] & 0x0f];
+            rc[j] = digits[(uuid_[i] >> 4) & 0x0f];
+            j+=2;
+        }
+        rc[j++] = '-';
+        for (size_t i = 4 ; i < 6; ++i) {
+            rc[j+1] = digits[uuid_[i] & 0x0f];
+            rc[j] = digits[(uuid_[i] >> 4) & 0x0f];
+            j+=2;
+        }
+        rc[j++] = '-';
+        for (size_t i = 6 ; i < 8; ++i) {
+            rc[j+1] = digits[uuid_[i] & 0x0f];
+            rc[j] = digits[(uuid_[i] >> 4) & 0x0f];
+            j+=2;
+        }
+        rc[j++] = '-';
+        for (size_t i = 8 ; i < 10; ++i) {
+            rc[j+1] = digits[uuid_[i] & 0x0f];
+            rc[j] = digits[(uuid_[i] >> 4) & 0x0f];
+            j+=2;
+        }
+        rc[j++] = '-';
+        for (size_t i = 10 ; i < 16; ++i) {
+            rc[j+1] = digits[uuid_[i] & 0x0f];
+            rc[j] = digits[(uuid_[i] >> 4) & 0x0f];
+            j+=2;
+        }
+        return rc;
 /* 
 #ifdef WIN32
-			RPC_CSTR szUuid = NULL;
-			if (::UuidToStringA(&guid_, &szUuid) == RPC_S_OK) {
-				return std::string((char*)szUuid);
-			}
-			return "00000000-0000-0000-0000-000000000000";
+        RPC_CSTR szUuid = NULL;
+        if (::UuidToStringA(&guid_, &szUuid) == RPC_S_OK) {
+            return std::string((char*)szUuid);
+        }
+        return "00000000-0000-0000-0000-000000000000";
 #else
-			char b[37];
-			uuid_unparse(uuid_, b);
-			return std::string(b);
+        char b[37];
+        uuid_unparse(uuid_, b);
+        return std::string(b);
 #endif
 */
-		}
-		
-		/* Allow the UUID to be packed into an RPC message. */
-		MSGPACK_DEFINE(uuid_);
-		
-		private:
+    }
+
+    /* Allow the UUID to be packed into an RPC message. */
+    MSGPACK_DEFINE(uuid_);
+
+ private:
 #ifdef WIN32
-		union {
-			_GUID guid_;
-			unsigned char uuid_[16];
-		};
+    union {
+        _GUID guid_;
+        unsigned char uuid_[16];
+    };
 #else
-		unsigned char uuid_[16];
+    unsigned char uuid_[16];
 #endif
-	};
 };
+}  // namespace ftl
 
 namespace std {
-	template <> struct hash<ftl::UUID> {
-		size_t operator()(const ftl::UUID & x) const {
-			return std::hash<std::string>{}(x.str());
-		}
-	};
+template <> struct hash<ftl::UUID> {
+    size_t operator()(const ftl::UUID & x) const {
+        return std::hash<std::string>{}(x.str());
+    }
 };
+}
diff --git a/src/base64.cpp b/src/base64.cpp
index a1be53b84b72f87ba937cd0f12ec5b0df8ab8c96..2eabe6c710016482a50b4475f8f59325f77d7266 100644
--- a/src/base64.cpp
+++ b/src/base64.cpp
@@ -1,84 +1,84 @@
 /*
-	base64.cpp and base64.h
+    base64.cpp and base64.h
 
-	base64 encoding and decoding with C++.
-	More information at
-		https://renenyffenegger.ch/notes/development/Base64/Encoding-and-decoding-base-64-with-cpp
+    base64 encoding and decoding with C++.
+    More information at
+        https://renenyffenegger.ch/notes/development/Base64/Encoding-and-decoding-base-64-with-cpp
 
-	Version: 2.rc.04 (release candidate)
+    Version: 2.rc.04 (release candidate)
 
-	Copyright (C) 2004-2017, 2020 René Nyffenegger
+    Copyright (C) 2004-2017, 2020 René Nyffenegger
 
-	This source code is provided 'as-is', without any express or implied
-	warranty. In no event will the author be held liable for any damages
-	arising from the use of this software.
+    This source code is provided 'as-is', without any express or implied
+    warranty. In no event will the author be held liable for any damages
+    arising from the use of this software.
 
-	Permission is granted to anyone to use this software for any purpose,
-	including commercial applications, and to alter it and redistribute it
-	freely, subject to the following restrictions:
+    Permission is granted to anyone to use this software for any purpose,
+    including commercial applications, and to alter it and redistribute it
+    freely, subject to the following restrictions:
 
-	1. The origin of this source code must not be misrepresented; you must not
-		claim that you wrote the original source code. If you use this source code
-		in a product, an acknowledgment in the product documentation would be
-		appreciated but is not required.
+    1. The origin of this source code must not be misrepresented; you must not
+        claim that you wrote the original source code. If you use this source code
+        in a product, an acknowledgment in the product documentation would be
+        appreciated but is not required.
 
-	2. Altered source versions must be plainly marked as such, and must not be
-		misrepresented as being the original source code.
+    2. Altered source versions must be plainly marked as such, and must not be
+        misrepresented as being the original source code.
 
-	3. This notice may not be removed or altered from any source distribution.
+    3. This notice may not be removed or altered from any source distribution.
 
-	René Nyffenegger rene.nyffenegger@adp-gmbh.ch
+    René Nyffenegger rene.nyffenegger@adp-gmbh.ch
 
 */
 
 #include <ftl/utility/base64.hpp>
 
- //
- // Depending on the url parameter in base64_chars, one of
- // two sets of base64 characters needs to be chosen.
- // They differ in their last two characters.
- //
+//
+// Depending on the url parameter in base64_chars, one of
+// two sets of base64 characters needs to be chosen.
+// They differ in their last two characters.
+//
 const char* base64_chars[2] = {
-			 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-			 "abcdefghijklmnopqrstuvwxyz"
-			 "0123456789"
-			 "+/",
+             "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+             "abcdefghijklmnopqrstuvwxyz"
+             "0123456789"
+             "+/",
 
-			 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-			 "abcdefghijklmnopqrstuvwxyz"
-			 "0123456789"
-			 "-_"};
+             "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+             "abcdefghijklmnopqrstuvwxyz"
+             "0123456789"
+             "-_"};
 
 static unsigned int pos_of_char(const unsigned char chr) {
- //
- // Return the position of chr within base64_encode()
- //
+//
+// Return the position of chr within base64_encode()
+//
 
-	if      (chr >= 'A' && chr <= 'Z') return chr - 'A';
-	else if (chr >= 'a' && chr <= 'z') return chr - 'a' + ('Z' - 'A')               + 1;
-	else if (chr >= '0' && chr <= '9') return chr - '0' + ('Z' - 'A') + ('z' - 'a') + 2;
-	else if (chr == '+' || chr == '-') return 62; // Be liberal with input and accept both url ('-') and non-url ('+') base 64 characters (
-	else if (chr == '/' || chr == '_') return 63; // Ditto for '/' and '_'
+    if      (chr >= 'A' && chr <= 'Z') return chr - 'A';
+    else if (chr >= 'a' && chr <= 'z') return chr - 'a' + ('Z' - 'A')               + 1;
+    else if (chr >= '0' && chr <= '9') return chr - '0' + ('Z' - 'A') + ('z' - 'a') + 2;
+    else if (chr == '+' || chr == '-') return 62; // Be liberal with input and accept both url ('-') and non-url ('+') base 64 characters (
+    else if (chr == '/' || chr == '_') return 63; // Ditto for '/' and '_'
 
-	throw "If input is correct, this line should never be reached.";
+    throw "If input is correct, this line should never be reached.";
 }
 
 static std::string insert_linebreaks(std::string str, size_t distance) {
- //
- // Provided by https://github.com/JomaCorpFX, adapted by me.
- //
-	if (!str.length()) {
-		return "";
-	}
+//
+// Provided by https://github.com/JomaCorpFX, adapted by me.
+//
+    if (!str.length()) {
+        return "";
+    }
 
-	size_t pos = distance;
+    size_t pos = distance;
 
-	while (pos < str.size()) {
-		str.insert(pos, "\n");
-		pos += distance + 1;
-	}
+    while (pos < str.size()) {
+        str.insert(pos, "\n");
+        pos += distance + 1;
+    }
 
-	return str;
+    return str;
 }
 
 template <typename String, unsigned int line_length>
@@ -103,131 +103,131 @@ static std::string encode(String s, bool url) {
 
 std::string base64_encode(unsigned char const* bytes_to_encode, size_t in_len, bool url) {
 
-	size_t len_encoded = (in_len +2) / 3 * 4;
+    size_t len_encoded = (in_len +2) / 3 * 4;
 
-	unsigned char trailing_char = url ? '.' : '=';
+    unsigned char trailing_char = url ? '.' : '=';
 
- //
- // Choose set of base64 characters. They differ
- // for the last two positions, depending on the url
- // parameter.
- // A bool (as is the parameter url) is guaranteed
- // to evaluate to either 0 or 1 in C++ therfore,
- // the correct character set is chosen by subscripting
- // base64_chars with url.
- //
-	const char* base64_chars_ = base64_chars[url];
+//
+// Choose set of base64 characters. They differ
+// for the last two positions, depending on the url
+// parameter.
+// A bool (as is the parameter url) is guaranteed
+// to evaluate to either 0 or 1 in C++ therfore,
+// the correct character set is chosen by subscripting
+// base64_chars with url.
+//
+    const char* base64_chars_ = base64_chars[url];
 
-	std::string ret;
-	ret.reserve(len_encoded);
+    std::string ret;
+    ret.reserve(len_encoded);
 
-	unsigned int pos = 0;
+    unsigned int pos = 0;
 
-	while (pos < in_len) {
-		ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0xfc) >> 2]);
+    while (pos < in_len) {
+        ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0xfc) >> 2]);
 
-		if (pos+1 < in_len) {
-			ret.push_back(base64_chars_[((bytes_to_encode[pos + 0] & 0x03) << 4) + ((bytes_to_encode[pos + 1] & 0xf0) >> 4)]);
+        if (pos+1 < in_len) {
+            ret.push_back(base64_chars_[((bytes_to_encode[pos + 0] & 0x03) << 4) + ((bytes_to_encode[pos + 1] & 0xf0) >> 4)]);
 
-			if (pos+2 < in_len) {
-				ret.push_back(base64_chars_[((bytes_to_encode[pos + 1] & 0x0f) << 2) + ((bytes_to_encode[pos + 2] & 0xc0) >> 6)]);
-				ret.push_back(base64_chars_[  bytes_to_encode[pos + 2] & 0x3f]);
-			}
-			else {
-				ret.push_back(base64_chars_[(bytes_to_encode[pos + 1] & 0x0f) << 2]);
-				ret.push_back(trailing_char);
-			}
-		}
-		else {
+            if (pos+2 < in_len) {
+                ret.push_back(base64_chars_[((bytes_to_encode[pos + 1] & 0x0f) << 2) + ((bytes_to_encode[pos + 2] & 0xc0) >> 6)]);
+                ret.push_back(base64_chars_[  bytes_to_encode[pos + 2] & 0x3f]);
+            }
+            else {
+                ret.push_back(base64_chars_[(bytes_to_encode[pos + 1] & 0x0f) << 2]);
+                ret.push_back(trailing_char);
+            }
+        }
+        else {
 
-			ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0x03) << 4]);
-			ret.push_back(trailing_char);
-			ret.push_back(trailing_char);
-		}
+            ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0x03) << 4]);
+            ret.push_back(trailing_char);
+            ret.push_back(trailing_char);
+        }
 
-		pos += 3;
-	}
+        pos += 3;
+    }
 
 
-	return ret;
+    return ret;
 }
 
 template <typename String>
 static std::string decode(String encoded_string, bool remove_linebreaks) {
- //
- // decode(…) is templated so that it can be used with String = const std::string&
- // or std::string_view (requires at least C++17)
- //
+//
+// decode(…) is templated so that it can be used with String = const std::string&
+// or std::string_view (requires at least C++17)
+//
 
-	if (remove_linebreaks) {
+    if (remove_linebreaks) {
 
-		if (! encoded_string.length() ) {
-			return "";
-		}
+        if (! encoded_string.length() ) {
+            return "";
+        }
 
-		std::string copy(encoded_string);
+        std::string copy(encoded_string);
 
-		size_t pos=0;
-		while ((pos = copy.find("\n", pos)) != std::string::npos) {
-			copy.erase(pos, 1);
-		}
+        size_t pos=0;
+        while ((pos = copy.find("\n", pos)) != std::string::npos) {
+            copy.erase(pos, 1);
+        }
 
-		return base64_decode(copy, false);
+        return base64_decode(copy, false);
 
-	}
+    }
 
-	size_t length_of_string = encoded_string.length();
-	if (!length_of_string) return std::string("");
+    size_t length_of_string = encoded_string.length();
+    if (!length_of_string) return std::string("");
 
-	size_t in_len = length_of_string;
-	size_t pos = 0;
+    size_t in_len = length_of_string;
+    size_t pos = 0;
 
- //
- // The approximate length (bytes) of the decoded string might be one ore
- // two bytes smaller, depending on the amount of trailing equal signs
- // in the encoded string. This approximation is needed to reserve
- // enough space in the string to be returned.
- //
-	size_t approx_length_of_decoded_string = length_of_string / 4 * 3;
-	std::string ret;
-	ret.reserve(approx_length_of_decoded_string);
+//
+// The approximate length (bytes) of the decoded string might be one ore
+// two bytes smaller, depending on the amount of trailing equal signs
+// in the encoded string. This approximation is needed to reserve
+// enough space in the string to be returned.
+//
+    size_t approx_length_of_decoded_string = length_of_string / 4 * 3;
+    std::string ret;
+    ret.reserve(approx_length_of_decoded_string);
 
-	while (pos < in_len) {
+    while (pos < in_len) {
 
-		unsigned int pos_of_char_1 = pos_of_char(encoded_string[pos+1] );
+        unsigned int pos_of_char_1 = pos_of_char(encoded_string[pos+1] );
 
-		ret.push_back(static_cast<std::string::value_type>( ( (pos_of_char(encoded_string[pos+0]) ) << 2 ) + ( (pos_of_char_1 & 0x30 ) >> 4)));
+        ret.push_back(static_cast<std::string::value_type>( ( (pos_of_char(encoded_string[pos+0]) ) << 2 ) + ( (pos_of_char_1 & 0x30 ) >> 4)));
 
-		if (encoded_string[pos+2] != '=' && encoded_string[pos+2] != '.') { // accept URL-safe base 64 strings, too, so check for '.' also.
+        if (encoded_string[pos+2] != '=' && encoded_string[pos+2] != '.') { // accept URL-safe base 64 strings, too, so check for '.' also.
 
-			unsigned int pos_of_char_2 = pos_of_char(encoded_string[pos+2] );
-			ret.push_back(static_cast<std::string::value_type>( (( pos_of_char_1 & 0x0f) << 4) + (( pos_of_char_2 & 0x3c) >> 2)));
+            unsigned int pos_of_char_2 = pos_of_char(encoded_string[pos+2] );
+            ret.push_back(static_cast<std::string::value_type>( (( pos_of_char_1 & 0x0f) << 4) + (( pos_of_char_2 & 0x3c) >> 2)));
 
-			if (encoded_string[pos+3] != '=' && encoded_string[pos+3] != '.') {
-				ret.push_back(static_cast<std::string::value_type>( ( (pos_of_char_2 & 0x03 ) << 6 ) + pos_of_char(encoded_string[pos+3])   ));
-			}
-		}
+            if (encoded_string[pos+3] != '=' && encoded_string[pos+3] != '.') {
+                ret.push_back(static_cast<std::string::value_type>( ( (pos_of_char_2 & 0x03 ) << 6 ) + pos_of_char(encoded_string[pos+3])   ));
+            }
+        }
 
-		pos += 4;
-	}
+        pos += 4;
+    }
 
-	return ret;
+    return ret;
 }
 
 std::string base64_decode(std::string const& s, bool remove_linebreaks) {
-	return decode(s, remove_linebreaks);
+    return decode(s, remove_linebreaks);
 }
 
 std::string base64_encode(std::string const& s, bool url) {
-	return encode(s, url);
+    return encode(s, url);
 }
 
 std::string base64_encode_pem (std::string const& s) {
-	return encode_pem(s);
+    return encode_pem(s);
 }
 
 std::string base64_encode_mime(std::string const& s) {
-	return encode_mime(s);
+    return encode_mime(s);
 }
 
 #if __cplusplus >= 201703L
@@ -238,19 +238,19 @@ std::string base64_encode_mime(std::string const& s) {
 //
 
 std::string base64_encode(std::string_view s, bool url) {
-	return encode(s, url);
+    return encode(s, url);
 }
 
 std::string base64_encode_pem(std::string_view s) {
-	return encode_pem(s);
+    return encode_pem(s);
 }
 
 std::string base64_encode_mime(std::string_view s) {
-	return encode_mime(s);
+    return encode_mime(s);
 }
 
 std::string base64_decode(std::string_view s, bool remove_linebreaks) {
-	return decode(s, remove_linebreaks);
+    return decode(s, remove_linebreaks);
 }
 
 #endif  // __cplusplus >= 201703L
diff --git a/src/channelSet.cpp b/src/channelSet.cpp
index 1340df450ad4af316259804bd44d81e33e66c9ee..c0c1702a83b02aeb0e93df3124bac404fa6b6a74 100644
--- a/src/channelSet.cpp
+++ b/src/channelSet.cpp
@@ -1,27 +1,33 @@
+/**
+ * @file channelSet.cpp
+ * @copyright Copyright (c) 2022 University of Turku, MIT License
+ * @author Nicolas Pope
+ */
+
 #include <ftl/protocol/channelSet.hpp>
 
 using ftl::protocol::ChannelSet;
 
 ChannelSet operator&(const ChannelSet &a, const ChannelSet &b) {
-	ChannelSet result;
-	for (auto &i : a) {
-		if (b.find(i) != b.end()) result.insert(i);
-	}
-	return result;
+    ChannelSet result;
+    for (auto &i : a) {
+        if (b.find(i) != b.end()) result.insert(i);
+    }
+    return result;
 }
 
 ChannelSet operator-(const ChannelSet &a, const ChannelSet &b) {
-	ChannelSet result;
-	for (auto &i : a) {
-		if (b.find(i) == b.end()) result.insert(i);
-	}
-	return result;
+    ChannelSet result;
+    for (auto &i : a) {
+        if (b.find(i) == b.end()) result.insert(i);
+    }
+    return result;
 }
 
 bool operator!=(const ChannelSet &a, const ChannelSet &b) {
-	if (a.size() != b.size()) return true;
-	for (auto &i : a) {
-		if (b.count(i) == 0) return true;
-	}
-	return false;
+    if (a.size() != b.size()) return true;
+    for (auto &i : a) {
+        if (b.count(i) == 0) return true;
+    }
+    return false;
 }
diff --git a/src/common.hpp b/src/common.hpp
index b64dab520d8eb1ab0ccb55cec2fabcf2da6af50e..a426778ad4a8037e103b09eba8ca1c6a7504f366 100644
--- a/src/common.hpp
+++ b/src/common.hpp
@@ -6,7 +6,7 @@
 
 #pragma once
 
-// TODO: remove platform specific headers from here
+// TODO(Nick): remove platform specific headers from here
 #ifndef WIN32
 #include <unistd.h>
 #include <sys/poll.h>
diff --git a/src/ctpl_stl.cpp b/src/ctpl_stl.cpp
index 2130650eaa34b8a28735290725c6fa4a9513a258..947560af1898aeec977e707f367959e75aebf701 100644
--- a/src/ctpl_stl.cpp
+++ b/src/ctpl_stl.cpp
@@ -6,14 +6,14 @@
 #include <ftl/lib/ctpl_stl.hpp>
 
 void ctpl::thread_pool::set_thread(int i) {
-    std::shared_ptr<std::atomic<bool>> flag(this->flags[i]); // a copy of the shared ptr to the flag
+    std::shared_ptr<std::atomic<bool>> flag(this->flags[i]);  // a copy of the shared ptr to the flag
     auto f = [this, i, flag/* a copy of the shared ptr to the flag */]() {
         std::atomic<bool> & _flag = *flag;
         std::function<void(int id)> * _f;
         bool isPop = this->q.pop(_f);
         while (true) {
             while (isPop) {  // if there is anything in the queue
-                std::unique_ptr<std::function<void(int id)>> func(_f); // at return, delete the function even if an exception occurred
+                std::unique_ptr<std::function<void(int id)>> func(_f);  // at return, delete the function even if an exception occurred
                 (*_f)(i);
                 if (_flag)
                     return;  // the thread is wanted to stop, return even if the queue is not empty yet
@@ -29,7 +29,7 @@ void ctpl::thread_pool::set_thread(int i) {
                 return;  // if the queue is empty and this->isDone == true or *flag then return
         }
     };
-    this->threads[i].reset(new std::thread(f)); // compiler may not support std::make_unique()
+    this->threads[i].reset(new std::thread(f));  // compiler may not support std::make_unique()
 
 	// For excess threads, ensure they only operate if needed.
 	/*if (i >= std::thread::hardware_concurrency()-1) {
diff --git a/src/dispatcher.cpp b/src/dispatcher.cpp
index bd4f721d8ff13f6d630bb5b030ce191083abe29c..57c9475f516496bdcab197e0f3936fb5bf4a2a9f 100644
--- a/src/dispatcher.cpp
+++ b/src/dispatcher.cpp
@@ -4,11 +4,11 @@
  * @author Nicolas Pope
  */
 
+#include <iostream>
 #include <ftl/lib/loguru.hpp>
 #include "dispatcher.hpp"
 #include "peer.hpp"
 #include <ftl/exception.hpp>
-#include <iostream>
 
 using ftl::net::Peer;
 using ftl::net::Dispatcher;
@@ -17,145 +17,142 @@ using std::string;
 using std::optional;
 
 std::string object_type_to_string(const msgpack::type::object_type t) {
-	switch(t) {
-		case msgpack::type::object_type::NIL: return "NIL";
-		case msgpack::type::object_type::BOOLEAN: return "BOOLEAN";
-		case msgpack::type::object_type::POSITIVE_INTEGER: return "POSITIVE_INTEGER";
-		case msgpack::type::object_type::NEGATIVE_INTEGER: return "NEGATIVE_INTEGER";
-		case msgpack::type::object_type::FLOAT32: return "FLOAT32";
-		case msgpack::type::object_type::FLOAT64: return "FLOAT64";
-		//case msgpack::type::object_type::FLOAT: return "FLOAT";
-		case msgpack::type::object_type::STR: return "STR";
-		case msgpack::type::object_type::BIN: return "BIN";
-		case msgpack::type::object_type::ARRAY: return "ARRAY";
-		case msgpack::type::object_type::MAP: return "MAP";
-		case msgpack::type::object_type::EXT: return "EXT";
-	}
-	return "UNKNOWN";
+    switch (t) {
+        case msgpack::type::object_type::NIL: return "NIL";
+        case msgpack::type::object_type::BOOLEAN: return "BOOLEAN";
+        case msgpack::type::object_type::POSITIVE_INTEGER: return "POSITIVE_INTEGER";
+        case msgpack::type::object_type::NEGATIVE_INTEGER: return "NEGATIVE_INTEGER";
+        case msgpack::type::object_type::FLOAT32: return "FLOAT32";
+        case msgpack::type::object_type::FLOAT64: return "FLOAT64";
+        case msgpack::type::object_type::STR: return "STR";
+        case msgpack::type::object_type::BIN: return "BIN";
+        case msgpack::type::object_type::ARRAY: return "ARRAY";
+        case msgpack::type::object_type::MAP: return "MAP";
+        case msgpack::type::object_type::EXT: return "EXT";
+    }
+    return "UNKNOWN";
 }
 
 vector<string> Dispatcher::getBindings() const {
-	vector<string> res;
-	for (auto x : funcs_) {
-		res.push_back(x.first);
-	}
-	return res;
+    vector<string> res;
+    for (auto x : funcs_) {
+        res.push_back(x.first);
+    }
+    return res;
 }
 
 void ftl::net::Dispatcher::dispatch(Peer &s, const msgpack::object &msg) {
-	switch (msg.via.array.size) {
-	case 3:
-		dispatch_notification(s, msg); break;
-	case 4:
-		dispatch_call(s, msg); break;
-	default:
-		throw FTL_Error("Unrecognised msgpack : " << msg.via.array.size);
-	}
+    switch (msg.via.array.size) {
+    case 3:
+        dispatch_notification(s, msg);
+        break;
+    case 4:
+        dispatch_call(s, msg);
+        break;
+    default:
+        throw FTL_Error("Unrecognised msgpack : " << msg.via.array.size);
+    }
 }
 
 void ftl::net::Dispatcher::dispatch_call(Peer &s, const msgpack::object &msg) {
-	call_t the_call;
-	
-	try {
-		msg.convert(the_call);
-	} catch(...) {
-		throw FTL_Error("Bad message format");
-	}
-
-	// TODO: proper validation of protocol (and responding to it)
-	auto &&type = std::get<0>(the_call);
-	auto &&id = std::get<1>(the_call);
-	auto &&name = std::get<2>(the_call);
-	auto &&args = std::get<3>(the_call);
-	// assert(type == 0);
-	
-	if (type == 1) {
-		s._dispatchResponse(id, name, args);
-	} else if (type == 0) {
-		DLOG(2) << "RPC " << name << "() <- " << s.getURI();
-
-		auto func = _locateHandler(name);
-
-		if (func) {
-			//DLOG(INFO) << "Found binding for " << name;
-			try {
-				auto result = (*func)(s, args); //->get();
-				s._sendResponse(id, name, result->get());
-			} catch (const std::exception &e) {
-				throw FTL_Error("Exception when attempting to call RPC " << name << " (" << e.what() << ")");
-				// FIXME: Send the error in the response.
-			}
-		} else {
-			throw FTL_Error("No binding found for " << name);
-		}
-	} else {
-		throw FTL_Error("Unrecognised message type: " << type);
-	}
+    call_t the_call;
+
+    try {
+        msg.convert(the_call);
+    } catch(...) {
+        throw FTL_Error("Bad message format");
+    }
+
+    // TODO(Nick): proper validation of protocol (and responding to it)
+    auto &&type = std::get<0>(the_call);
+    auto &&id = std::get<1>(the_call);
+    auto &&name = std::get<2>(the_call);
+    auto &&args = std::get<3>(the_call);
+    // assert(type == 0);
+
+    if (type == 1) {
+        s._dispatchResponse(id, name, args);
+    } else if (type == 0) {
+        DLOG(2) << "RPC " << name << "() <- " << s.getURI();
+
+        auto func = _locateHandler(name);
+
+        if (func) {
+            try {
+                auto result = (*func)(s, args);
+                s._sendResponse(id, name, result->get());
+            } catch (const std::exception &e) {
+                throw FTL_Error("Exception when attempting to call RPC " << name << " (" << e.what() << ")");
+                // FIXME: Send the error in the response.
+            }
+        } else {
+            throw FTL_Error("No binding found for " << name);
+        }
+    } else {
+        throw FTL_Error("Unrecognised message type: " << type);
+    }
 }
 
 optional<Dispatcher::adaptor_type> ftl::net::Dispatcher::_locateHandler(const std::string &name) const {
-	auto it_func = funcs_.find(name);
-	if (it_func == funcs_.end()) {
-		if (parent_ != nullptr) {
-			return parent_->_locateHandler(name);
-		} else {
-			return {};
-		}
-	} else {
-		return it_func->second;
-	}
+    auto it_func = funcs_.find(name);
+    if (it_func == funcs_.end()) {
+        if (parent_ != nullptr) {
+            return parent_->_locateHandler(name);
+        } else {
+            return {};
+        }
+    } else {
+        return it_func->second;
+    }
 }
 
 bool ftl::net::Dispatcher::isBound(const std::string &name) const {
-	return funcs_.find(name) != funcs_.end();
+    return funcs_.find(name) != funcs_.end();
 }
 
 void ftl::net::Dispatcher::dispatch_notification(Peer &s, msgpack::object const &msg) {
-	notification_t the_call;
-	msg.convert(the_call);
-
-	// TODO: proper validation of protocol (and responding to it)
-	// auto &&type = std::get<0>(the_call);
-	// assert(type == static_cast<uint8_t>(request_type::notification));
-
-	auto &&name = std::get<1>(the_call);
-	auto &&args = std::get<2>(the_call);
-
-	auto binding = _locateHandler(name);
-
-	if (binding) {
-		try {
-			auto result = (*binding)(s, args);
-		} catch (const int &e) {
-			//throw "Exception in bound function";
-			throw &e;
-		} catch (const std::bad_cast &e) {
-			std::string args_str = "";
-			for (size_t i = 0; i < args.via.array.size; i++) {
-				args_str += object_type_to_string(args.via.array.ptr[i].type);
-				if ((i + 1) != args.via.array.size) args_str += ", ";
-			}
-			throw FTL_Error("Bad cast, got: " << args_str);
-
-		} catch (const std::exception &e) {
-			throw FTL_Error("Exception for '" << name << "' - " << e.what());
-		}
-	} else {
-		throw FTL_Error("Missing handler for incoming message (" << name << ")");
-	}
+    notification_t the_call;
+    msg.convert(the_call);
+
+    // TODO(Nick): proper validation of protocol (and responding to it)
+    // auto &&type = std::get<0>(the_call);
+    // assert(type == static_cast<uint8_t>(request_type::notification));
+
+    auto &&name = std::get<1>(the_call);
+    auto &&args = std::get<2>(the_call);
+
+    auto binding = _locateHandler(name);
+
+    if (binding) {
+        try {
+            auto result = (*binding)(s, args);
+        } catch (const int &e) {
+            throw &e;
+        } catch (const std::bad_cast &e) {
+            std::string args_str = "";
+            for (size_t i = 0; i < args.via.array.size; i++) {
+                args_str += object_type_to_string(args.via.array.ptr[i].type);
+                if ((i + 1) != args.via.array.size) args_str += ", ";
+            }
+            throw FTL_Error("Bad cast, got: " << args_str);
+        } catch (const std::exception &e) {
+            throw FTL_Error("Exception for '" << name << "' - " << e.what());
+        }
+    } else {
+        throw FTL_Error("Missing handler for incoming message (" << name << ")");
+    }
 }
 
 void ftl::net::Dispatcher::enforce_arg_count(std::string const &func, std::size_t found,
-								   std::size_t expected) {
-	if (found != expected) {
-		throw FTL_Error("RPC argument missmatch for '" << func << "' - " << found << " != " << expected);
-	}
+                                   std::size_t expected) {
+    if (found != expected) {
+        throw FTL_Error("RPC argument missmatch for '" << func << "' - " << found << " != " << expected);
+    }
 }
 
 void ftl::net::Dispatcher::enforce_unique_name(std::string const &func) {
-	auto pos = funcs_.find(func);
-	if (pos != end(funcs_)) {
-		throw FTL_Error("RPC non unique binding for '" << func << "'");
-	}
+    auto pos = funcs_.find(func);
+    if (pos != end(funcs_)) {
+        throw FTL_Error("RPC non unique binding for '" << func << "'");
+    }
 }
-
diff --git a/src/dispatcher.hpp b/src/dispatcher.hpp
index ec2dada9a87e0d59ae086e081d0c109ba4917357..c7f89274ff364e40a59aaefe2ec99cd899afc2a8 100644
--- a/src/dispatcher.hpp
+++ b/src/dispatcher.hpp
@@ -6,10 +6,6 @@
 
 #pragma once
 
-#include "func_traits.hpp"
-
-#include <msgpack.hpp>
-
 #include <memory>
 #include <tuple>
 #include <functional>
@@ -18,6 +14,11 @@
 #include <string>
 #include <unordered_map>
 #include <optional>
+#include <utility>
+
+#include "func_traits.hpp"
+
+#include <msgpack.hpp>
 
 namespace ftl {
 
@@ -26,39 +27,38 @@ class Peer;
 }
 
 namespace internal {
-	//! \brief Calls a functor with argument provided directly
-	template <typename Functor, typename Arg>
-	auto call(Functor f, Arg &&arg)
-		-> decltype(f(std::forward<Arg>(arg)))
-	{
-		return f(std::forward<Arg>(arg));
-	}
-
-	template <typename Functor, typename... Args, std::size_t... I>
-	decltype(auto) call_helper(Functor func, std::tuple<Args...> &&params,
-		                       std::index_sequence<I...>) {
-		return func(std::get<I>(params)...);
-	}
-
-	template <typename Functor, typename... Args, std::size_t... I>
-	decltype(auto) call_helper(Functor func, ftl::net::Peer &p, std::tuple<Args...> &&params,
-		                       std::index_sequence<I...>) {
-		return func(p, std::get<I>(params)...);
-	}
-
-	//! \brief Calls a functor with arguments provided as a tuple
-	template <typename Functor, typename... Args>
-	decltype(auto) call(Functor f, std::tuple<Args...> &args) {
-		return call_helper(f, std::forward<std::tuple<Args...>>(args),
-		                   std::index_sequence_for<Args...>{});
-	}
-
-	//! \brief Calls a functor with arguments provided as a tuple
-	template <typename Functor, typename... Args>
-	decltype(auto) call(Functor f, ftl::net::Peer &p, std::tuple<Args...> &args) {
-		return call_helper(f, p, std::forward<std::tuple<Args...>>(args),
-		                   std::index_sequence_for<Args...>{});
-	}
+    //! \brief Calls a functor with argument provided directly
+    template <typename Functor, typename Arg>
+    auto call(Functor f, Arg &&arg)
+        -> decltype(f(std::forward<Arg>(arg))) {
+        return f(std::forward<Arg>(arg));
+    }
+
+    template <typename Functor, typename... Args, std::size_t... I>
+    decltype(auto) call_helper(Functor func, std::tuple<Args...> &&params,
+                               std::index_sequence<I...>) {
+        return func(std::get<I>(params)...);
+    }
+
+    template <typename Functor, typename... Args, std::size_t... I>
+    decltype(auto) call_helper(Functor func, ftl::net::Peer &p, std::tuple<Args...> &&params,
+                               std::index_sequence<I...>) {
+        return func(p, std::get<I>(params)...);
+    }
+
+    //! \brief Calls a functor with arguments provided as a tuple
+    template <typename Functor, typename... Args>
+    decltype(auto) call(Functor f, std::tuple<Args...> &args) {
+        return call_helper(f, std::forward<std::tuple<Args...>>(args),
+                           std::index_sequence_for<Args...>{});
+    }
+
+    //! \brief Calls a functor with arguments provided as a tuple
+    template <typename Functor, typename... Args>
+    decltype(auto) call(Functor f, ftl::net::Peer &p, std::tuple<Args...> &args) {
+        return call_helper(f, p, std::forward<std::tuple<Args...>>(args),
+                           std::index_sequence_for<Args...>{});
+    }
 }
 
 namespace net {
@@ -69,213 +69,213 @@ namespace net {
  * arguments). Used by ftl::net::Peer and Universe.
  */
 class Dispatcher {
-	public:
-	explicit Dispatcher(Dispatcher *parent=nullptr) : parent_(parent) {
-		// FIXME: threading and funcs_; hack use large size
-		funcs_.reserve(1024);
-	}
-
-	/**
-	 * Primary method by which a peer dispatches a msgpack object that this
-	 * class then decodes to find correct handler and types.
-	 */
-	void dispatch(ftl::net::Peer &, const msgpack::object &msg);
-
-	// Without peer object =====================================================
-
-	/**
-	 * Associate a C++ function woth a string name. Use type traits of that
-	 * function to build a dispatch function that knows how to decode msgpack.
-	 * This is the no arguments and no result case.
-	 */
-	template <typename F>
-	void bind(std::string const &name, F func,
-		                  ftl::internal::tags::void_result const &,
-		                  ftl::internal::tags::zero_arg const &,
-						  ftl::internal::false_ const &) {
-		enforce_unique_name(name);
-		funcs_.insert(
-		    std::make_pair(name, [func, name](ftl::net::Peer &p, msgpack::object const &args) {
-		        enforce_arg_count(name, 0, args.via.array.size);
-		        func();
-		        return std::make_unique<msgpack::object_handle>();
-		    }));
-	}
-
-	/**
-	 * Associate a C++ function woth a string name. Use type traits of that
-	 * function to build a dispatch function that knows how to decode msgpack.
-	 * This is the arguments but no result case.
-	 */
-	template <typename F>
-	void bind(std::string const &name, F func,
-		                  ftl::internal::tags::void_result const &,
-		                  ftl::internal::tags::nonzero_arg const &,
-						  ftl::internal::false_ const &) {
-		using ftl::internal::func_traits;
-		using args_type = typename func_traits<F>::args_type;
-
-		enforce_unique_name(name);
-		funcs_.insert(
-		    std::make_pair(name, [func, name](ftl::net::Peer &p, msgpack::object const &args) {
-		        constexpr int args_count = std::tuple_size<args_type>::value;
-		        enforce_arg_count(name, args_count, args.via.array.size);
-		        args_type args_real;
-		        args.convert(args_real);
-		        ftl::internal::call(func, args_real);
-		        return std::make_unique<msgpack::object_handle>();
-		    }));
-	}
-
-	/**
-	 * Associate a C++ function woth a string name. Use type traits of that
-	 * function to build a dispatch function that knows how to decode msgpack.
-	 * This is the no arguments but with result case.
-	 */
-	template <typename F>
-	void bind(std::string const &name, F func,
-		                  ftl::internal::tags::nonvoid_result const &,
-		                  ftl::internal::tags::zero_arg const &,
-						  ftl::internal::false_ const &) {
-		using ftl::internal::func_traits;
-
-		enforce_unique_name(name);
-		funcs_.insert(std::make_pair(name, [func,
-		                                    name](ftl::net::Peer &p, msgpack::object const &args) {
-		    enforce_arg_count(name, 0, args.via.array.size);
-		    auto z = std::make_unique<msgpack::zone>();
-		    auto result = msgpack::object(func(), *z);
-		    return std::make_unique<msgpack::object_handle>(result, std::move(z));
-		}));
-	}
-
-	/**
-	 * Associate a C++ function woth a string name. Use type traits of that
-	 * function to build a dispatch function that knows how to decode msgpack.
-	 * This is the with arguments and with result case.
-	 */
-	template <typename F>
-	void bind(std::string const &name, F func,
-		                  ftl::internal::tags::nonvoid_result const &,
-		                  ftl::internal::tags::nonzero_arg const &,
-						  ftl::internal::false_ const &) {
-		using ftl::internal::func_traits;
-		using args_type = typename func_traits<F>::args_type;
-
-		enforce_unique_name(name);
-		funcs_.insert(std::make_pair(name, [func,
-		                                    name](ftl::net::Peer &p, msgpack::object const &args) {
-		    constexpr int args_count = std::tuple_size<args_type>::value;
-		    enforce_arg_count(name, args_count, args.via.array.size);
-		    args_type args_real;
-		    args.convert(args_real);
-		    auto z = std::make_unique<msgpack::zone>();
-		    auto result = msgpack::object(ftl::internal::call(func, args_real), *z);
-		    return std::make_unique<msgpack::object_handle>(result, std::move(z));
-		}));
-	}
-
-	// With peer object ========================================================
-
-	template <typename F>
-	void bind(std::string const &name, F func,
-		                  ftl::internal::tags::void_result const &,
-		                  ftl::internal::tags::zero_arg const &,
-						  ftl::internal::true_ const &) {
-		enforce_unique_name(name);
-		funcs_.insert(
-		    std::make_pair(name, [func, name](ftl::net::Peer &p, msgpack::object const &args) {
-		        enforce_arg_count(name, 0, args.via.array.size);
-		        func(p);
-		        return std::make_unique<msgpack::object_handle>();
-		    }));
-	}
-
-	template <typename F>
-	void bind(std::string const &name, F func,
-		                  ftl::internal::tags::void_result const &,
-		                  ftl::internal::tags::nonzero_arg const &,
-						  ftl::internal::true_ const &) {
-		using ftl::internal::func_traits;
-		using args_type = typename func_traits<F>::args_type;
-
-		enforce_unique_name(name);
-		funcs_.insert(
-		    std::make_pair(name, [func, name](ftl::net::Peer &p, msgpack::object const &args) {
-		        constexpr int args_count = std::tuple_size<args_type>::value;
-		        enforce_arg_count(name, args_count, args.via.array.size);
-		        args_type args_real;
-		        args.convert(args_real);
-		        ftl::internal::call(func, p, args_real);
-		        return std::make_unique<msgpack::object_handle>();
-		    }));
-	}
-
-	template <typename F>
-	void bind(std::string const &name, F func,
-		                  ftl::internal::tags::nonvoid_result const &,
-		                  ftl::internal::tags::zero_arg const &,
-						  ftl::internal::true_ const &) {
-		using ftl::internal::func_traits;
-
-		enforce_unique_name(name);
-		funcs_.insert(std::make_pair(name, [func,
-		                                    name](ftl::net::Peer &p, msgpack::object const &args) {
-		    enforce_arg_count(name, 0, args.via.array.size);
-		    auto z = std::make_unique<msgpack::zone>();
-		    auto result = msgpack::object(func(p), *z);
-		    return std::make_unique<msgpack::object_handle>(result, std::move(z));
-		}));
-	}
-
-	template <typename F>
-	void bind(std::string const &name, F func,
-		                  ftl::internal::tags::nonvoid_result const &,
-		                  ftl::internal::tags::nonzero_arg const &,
-						  ftl::internal::true_ const &) {
-		using ftl::internal::func_traits;
-		using args_type = typename func_traits<F>::args_type;
-
-		enforce_unique_name(name);
-		funcs_.insert(std::make_pair(name, [func,
-		                                    name](ftl::net::Peer &p, msgpack::object const &args) {
-		    constexpr int args_count = std::tuple_size<args_type>::value;
-		    enforce_arg_count(name, args_count, args.via.array.size);
-		    args_type args_real;
-		    args.convert(args_real);
-		    auto z = std::make_unique<msgpack::zone>();
-		    auto result = msgpack::object(ftl::internal::call(func, p, args_real), *z);
-		    return std::make_unique<msgpack::object_handle>(result, std::move(z));
-		}));
-	}
-
-	//==========================================================================
-
-	/**
-	 * Remove a previous bound function by name.
-	 */
-	void unbind(const std::string &name) {
-		auto i = funcs_.find(name);
-		if (i != funcs_.end()) {
-			funcs_.erase(i);
-		}
-	}
-
-	/**
-	 * @return All bound function names.
-	 */
-	std::vector<std::string> getBindings() const;
-
-	/**
-	 * @param name Function name.
-	 * @return True if the given name is bound to a function.
-	 */
-	bool isBound(const std::string &name) const;
-
-
-	//==== Types ===============================================================
-
-	using adaptor_type = std::function<std::unique_ptr<msgpack::object_handle>(
+ public:
+    explicit Dispatcher(Dispatcher *parent = nullptr) : parent_(parent) {
+        // FIXME: threading and funcs_; hack use large size
+        funcs_.reserve(1024);
+    }
+
+    /**
+     * Primary method by which a peer dispatches a msgpack object that this
+     * class then decodes to find correct handler and types.
+     */
+    void dispatch(ftl::net::Peer &, const msgpack::object &msg);
+
+    // Without peer object =====================================================
+
+    /**
+     * Associate a C++ function woth a string name. Use type traits of that
+     * function to build a dispatch function that knows how to decode msgpack.
+     * This is the no arguments and no result case.
+     */
+    template <typename F>
+    void bind(std::string const &name, F func,
+                          ftl::internal::tags::void_result const &,
+                          ftl::internal::tags::zero_arg const &,
+                          ftl::internal::false_ const &) {
+        enforce_unique_name(name);
+        funcs_.insert(
+            std::make_pair(name, [func, name](ftl::net::Peer &p, msgpack::object const &args) {
+                enforce_arg_count(name, 0, args.via.array.size);
+                func();
+                return std::make_unique<msgpack::object_handle>();
+            }));
+    }
+
+    /**
+     * Associate a C++ function woth a string name. Use type traits of that
+     * function to build a dispatch function that knows how to decode msgpack.
+     * This is the arguments but no result case.
+     */
+    template <typename F>
+    void bind(std::string const &name, F func,
+                          ftl::internal::tags::void_result const &,
+                          ftl::internal::tags::nonzero_arg const &,
+                          ftl::internal::false_ const &) {
+        using ftl::internal::func_traits;
+        using args_type = typename func_traits<F>::args_type;
+
+        enforce_unique_name(name);
+        funcs_.insert(
+            std::make_pair(name, [func, name](ftl::net::Peer &p, msgpack::object const &args) {
+                constexpr int args_count = std::tuple_size<args_type>::value;
+                enforce_arg_count(name, args_count, args.via.array.size);
+                args_type args_real;
+                args.convert(args_real);
+                ftl::internal::call(func, args_real);
+                return std::make_unique<msgpack::object_handle>();
+            }));
+    }
+
+    /**
+     * Associate a C++ function woth a string name. Use type traits of that
+     * function to build a dispatch function that knows how to decode msgpack.
+     * This is the no arguments but with result case.
+     */
+    template <typename F>
+    void bind(std::string const &name, F func,
+                          ftl::internal::tags::nonvoid_result const &,
+                          ftl::internal::tags::zero_arg const &,
+                          ftl::internal::false_ const &) {
+        using ftl::internal::func_traits;
+
+        enforce_unique_name(name);
+        funcs_.insert(std::make_pair(name, [func,
+                                            name](ftl::net::Peer &p, msgpack::object const &args) {
+            enforce_arg_count(name, 0, args.via.array.size);
+            auto z = std::make_unique<msgpack::zone>();
+            auto result = msgpack::object(func(), *z);
+            return std::make_unique<msgpack::object_handle>(result, std::move(z));
+        }));
+    }
+
+    /**
+     * Associate a C++ function woth a string name. Use type traits of that
+     * function to build a dispatch function that knows how to decode msgpack.
+     * This is the with arguments and with result case.
+     */
+    template <typename F>
+    void bind(std::string const &name, F func,
+                          ftl::internal::tags::nonvoid_result const &,
+                          ftl::internal::tags::nonzero_arg const &,
+                          ftl::internal::false_ const &) {
+        using ftl::internal::func_traits;
+        using args_type = typename func_traits<F>::args_type;
+
+        enforce_unique_name(name);
+        funcs_.insert(std::make_pair(name, [func,
+                                            name](ftl::net::Peer &p, msgpack::object const &args) {
+            constexpr int args_count = std::tuple_size<args_type>::value;
+            enforce_arg_count(name, args_count, args.via.array.size);
+            args_type args_real;
+            args.convert(args_real);
+            auto z = std::make_unique<msgpack::zone>();
+            auto result = msgpack::object(ftl::internal::call(func, args_real), *z);
+            return std::make_unique<msgpack::object_handle>(result, std::move(z));
+        }));
+    }
+
+    // With peer object ========================================================
+
+    template <typename F>
+    void bind(std::string const &name, F func,
+                          ftl::internal::tags::void_result const &,
+                          ftl::internal::tags::zero_arg const &,
+                          ftl::internal::true_ const &) {
+        enforce_unique_name(name);
+        funcs_.insert(
+            std::make_pair(name, [func, name](ftl::net::Peer &p, msgpack::object const &args) {
+                enforce_arg_count(name, 0, args.via.array.size);
+                func(p);
+                return std::make_unique<msgpack::object_handle>();
+            }));
+    }
+
+    template <typename F>
+    void bind(std::string const &name, F func,
+                          ftl::internal::tags::void_result const &,
+                          ftl::internal::tags::nonzero_arg const &,
+                          ftl::internal::true_ const &) {
+        using ftl::internal::func_traits;
+        using args_type = typename func_traits<F>::args_type;
+
+        enforce_unique_name(name);
+        funcs_.insert(
+            std::make_pair(name, [func, name](ftl::net::Peer &p, msgpack::object const &args) {
+                constexpr int args_count = std::tuple_size<args_type>::value;
+                enforce_arg_count(name, args_count, args.via.array.size);
+                args_type args_real;
+                args.convert(args_real);
+                ftl::internal::call(func, p, args_real);
+                return std::make_unique<msgpack::object_handle>();
+            }));
+    }
+
+    template <typename F>
+    void bind(std::string const &name, F func,
+                          ftl::internal::tags::nonvoid_result const &,
+                          ftl::internal::tags::zero_arg const &,
+                          ftl::internal::true_ const &) {
+        using ftl::internal::func_traits;
+
+        enforce_unique_name(name);
+        funcs_.insert(std::make_pair(name, [func,
+                                            name](ftl::net::Peer &p, msgpack::object const &args) {
+            enforce_arg_count(name, 0, args.via.array.size);
+            auto z = std::make_unique<msgpack::zone>();
+            auto result = msgpack::object(func(p), *z);
+            return std::make_unique<msgpack::object_handle>(result, std::move(z));
+        }));
+    }
+
+    template <typename F>
+    void bind(std::string const &name, F func,
+                          ftl::internal::tags::nonvoid_result const &,
+                          ftl::internal::tags::nonzero_arg const &,
+                          ftl::internal::true_ const &) {
+        using ftl::internal::func_traits;
+        using args_type = typename func_traits<F>::args_type;
+
+        enforce_unique_name(name);
+        funcs_.insert(std::make_pair(name, [func,
+                                            name](ftl::net::Peer &p, msgpack::object const &args) {
+            constexpr int args_count = std::tuple_size<args_type>::value;
+            enforce_arg_count(name, args_count, args.via.array.size);
+            args_type args_real;
+            args.convert(args_real);
+            auto z = std::make_unique<msgpack::zone>();
+            auto result = msgpack::object(ftl::internal::call(func, p, args_real), *z);
+            return std::make_unique<msgpack::object_handle>(result, std::move(z));
+        }));
+    }
+
+    //==========================================================================
+
+    /**
+     * Remove a previous bound function by name.
+     */
+    void unbind(const std::string &name) {
+        auto i = funcs_.find(name);
+        if (i != funcs_.end()) {
+            funcs_.erase(i);
+        }
+    }
+
+    /**
+     * @return All bound function names.
+     */
+    std::vector<std::string> getBindings() const;
+
+    /**
+     * @param name Function name.
+     * @return True if the given name is bound to a function.
+     */
+    bool isBound(const std::string &name) const;
+
+
+    //==== Types ===============================================================
+
+    using adaptor_type = std::function<std::unique_ptr<msgpack::object_handle>(
         ftl::net::Peer &, msgpack::object const &)>;
 
     //! \brief This is the type of messages as per the msgpack-rpc spec.
@@ -287,20 +287,20 @@ class Dispatcher {
     using response_t =
         std::tuple<uint32_t, uint32_t, std::string, msgpack::object>;
 
-	private:
-	Dispatcher *parent_;
-	std::unordered_map<std::string, adaptor_type> funcs_;
+ private:
+    Dispatcher *parent_;
+    std::unordered_map<std::string, adaptor_type> funcs_;
 
-	std::optional<adaptor_type> _locateHandler(const std::string &name) const;
+    std::optional<adaptor_type> _locateHandler(const std::string &name) const;
 
-	static void enforce_arg_count(std::string const &func, std::size_t found,
+    static void enforce_arg_count(std::string const &func, std::size_t found,
                                   std::size_t expected);
 
     void enforce_unique_name(std::string const &func);
 
-	void dispatch_call(ftl::net::Peer &, const msgpack::object &msg);
-	void dispatch_notification(ftl::net::Peer &, msgpack::object const &msg);
+    void dispatch_call(ftl::net::Peer &, const msgpack::object &msg);
+    void dispatch_notification(ftl::net::Peer &, msgpack::object const &msg);
 };
 
-}
-}
+}  // namespace net
+}  // namespace ftl
diff --git a/src/exception.cpp b/src/exception.cpp
index 9a337a073fda866ab495e64644d189368faba460..8ab442cc041bde3464a3c3a186c2f3f3557ffb18 100644
--- a/src/exception.cpp
+++ b/src/exception.cpp
@@ -15,19 +15,18 @@
 #include <cxxabi.h>
 
 std::string demangle(const char* name) {
-	if (!name) {
-		return "[unknown symbol]";
-	}
-	int status;
-	char* demangled = abi::__cxa_demangle(name, NULL, 0, &status);
-	if (!demangled) {
-		return std::string(name);
-	}
-	else {
-		auto result = std::string(demangled);
-		free(demangled);
-		return result;
-	}
+    if (!name) {
+        return "[unknown symbol]";
+    }
+    int status;
+    char* demangled = abi::__cxa_demangle(name, NULL, 0, &status);
+    if (!demangled) {
+        return std::string(name);
+    } else {
+        auto result = std::string(demangled);
+        free(demangled);
+        return result;
+    }
 }
 
 #endif
@@ -36,71 +35,70 @@ using ftl::exception;
 using std::string;
 
 string addr_to_string(const void* addr) {
-	std::stringstream ss;
-	ss << addr;
-	return ss.str();
+    std::stringstream ss;
+    ss << addr;
+    return ss.str();
 }
 
 #ifdef __GNUC__
 string exception::decode_backtrace() const {
-	string result;
-	// backtrace_symbols() as fallback (no data from dladdr())
-	char **messages = backtrace_symbols(trace_, trace_size_);
-
-	if (!messages) {
-		return string("[bt] no trace");
-	}
-
-	/* skip first stack frame (points here) */
-	for (int i=1; i < trace_size_; ++i) {
-		result += string("[bt] #") + std::to_string(i-1)
-				+ string(TRACE_SIZE_MAX_/10 - (i-1)/10, ' ')
-				+ string(" ");
-
-		Dl_info info;
-		if (dladdr(trace_[i], &info) && info.dli_saddr) {
-			auto name = demangle(info.dli_sname);
-			string fname = info.dli_fname ? info.dli_fname: "[unknown file]";
-
-			result += fname +
-				+ "           "
-				+ " [" + addr_to_string(info.dli_saddr) + "]" // exact address of symbol
-				+ string(", in ")
-				+ name;
-		}
-		else {
-			result += messages[i];
-		}
-		result += "\n";
-	}
-
-	free(messages);
-	return result;
+    string result;
+    // backtrace_symbols() as fallback (no data from dladdr())
+    char **messages = backtrace_symbols(trace_, trace_size_);
+
+    if (!messages) {
+        return string("[bt] no trace");
+    }
+
+    /* skip first stack frame (points here) */
+    for (int i=1; i < trace_size_; ++i) {
+        result += string("[bt] #") + std::to_string(i-1)
+                + string(TRACE_SIZE_MAX_/10 - (i-1)/10, ' ')
+                + string(" ");
+
+        Dl_info info;
+        if (dladdr(trace_[i], &info) && info.dli_saddr) {
+            auto name = demangle(info.dli_sname);
+            string fname = info.dli_fname ? info.dli_fname: "[unknown file]";
+
+            result += fname +
+                + "           "
+                + " [" + addr_to_string(info.dli_saddr) + "]"  // exact address of symbol
+                + string(", in ")
+                + name;
+        } else {
+            result += messages[i];
+        }
+        result += "\n";
+    }
+
+    free(messages);
+    return result;
 }
 
 #else
 string exception::decode_backtrace() const {
-	return string();
+    return string();
 }
 #endif
 
 exception::exception(const char *msg) : msg_(msg), processed_(false) {
-	#ifdef __GNUC__
-	trace_size_ = backtrace(trace_, TRACE_SIZE_MAX_);
-	#endif
+    #ifdef __GNUC__
+    trace_size_ = backtrace(trace_, TRACE_SIZE_MAX_);
+    #endif
 }
 
 exception::exception(const ftl::Formatter &msg) : msg_(msg.str()), processed_(false) {
-	#ifdef __GNUC__
-	trace_size_ = backtrace(trace_, TRACE_SIZE_MAX_);
-	#endif
+    #ifdef __GNUC__
+    trace_size_ = backtrace(trace_, TRACE_SIZE_MAX_);
+    #endif
 }
 
 exception::~exception() {
-	if (!processed_) { // what() or ignore() have not been called.
-		LOG(ERROR) << "Unhandled exception: " << what();
-		#ifdef __GNUC__
-		LOG(ERROR) << "Trace:\n" << decode_backtrace();
-		#endif
-	}
+    if (!processed_) {  // what() or ignore() have not been called.
+        LOG(ERROR) << "Unhandled exception: " << what();
+        #ifdef __GNUC__
+        LOG(ERROR) << "Trace:\n" << decode_backtrace();
+        #endif
+    }
 }
diff --git a/src/func_traits.hpp b/src/func_traits.hpp
index 1008f364d514a8652858882bc0883d136dbade9e..e2ce5e57e2ebd36340e853c18d4f40e79179c2f1 100644
--- a/src/func_traits.hpp
+++ b/src/func_traits.hpp
@@ -43,14 +43,22 @@ struct nonzero_arg {};
 struct void_result {};
 struct nonvoid_result {};
 
-template <int N> struct arg_count_trait { typedef nonzero_arg type; };
+template <int N> struct arg_count_trait {
+    typedef nonzero_arg type;
+};
 
-template <> struct arg_count_trait<0> { typedef zero_arg type; };
+template <> struct arg_count_trait<0> {
+    typedef zero_arg type;
+};
 
-template <typename T> struct result_trait { typedef nonvoid_result type; };
+template <typename T> struct result_trait {
+    typedef nonvoid_result type;
+};
 
-template <> struct result_trait<void> { typedef void_result type; };
-}
+template <> struct result_trait<void> {
+    typedef void_result type;
+};
+}  // namespace tags
 
 //! \brief Provides a small function traits implementation that
 //! works with a reasonably large set of functors.
@@ -63,7 +71,7 @@ struct func_traits<R (C::*)(Args...)> : func_traits<R (*)(Args...)> {};
 template <typename C, typename R, typename... Args>
 struct func_traits<R (C::*)(Args...) const> : func_traits<R (*)(Args...)> {};
 
-template <typename R, typename... Args> struct func_traits<R (*)(ftl::net::Peer &,Args...)> {
+template <typename R, typename... Args> struct func_traits<R (*)(ftl::net::Peer &, Args...)> {
     using result_type = R;
     using arg_count = std::integral_constant<std::size_t, sizeof...(Args)>;
     using args_type = std::tuple<typename std::decay<Args>::type...>;
@@ -75,8 +83,8 @@ template <typename R, typename... Args> struct func_traits<R (*)(Args...)> {
     using args_type = std::tuple<typename std::decay<Args>::type...>;
 };
 
-//template <typename T>
-//auto bindThis(F f, T t) { return [f,t]()t.f(42, std::forward<decltype(arg)>(arg)); }
+// template <typename T>
+// auto bindThis(F f, T t) { return [f,t]()t.f(42, std::forward<decltype(arg)>(arg)); }
 
 template <typename T>
 struct func_kind_info : func_kind_info<decltype(&T::operator())> {};
@@ -84,23 +92,23 @@ struct func_kind_info : func_kind_info<decltype(&T::operator())> {};
 template <typename C, typename R, typename... Args>
 struct func_kind_info<R (C::*)(Args...)> : func_kind_info<R (*)(Args...)> {};
 
-//template <typename R, typename... Args>
-//struct func_kind_info<std::_Bind<R(Args...)>> : func_kind_info<R(*)(Args...)> {};
+// template <typename R, typename... Args>
+// struct func_kind_info<std::_Bind<R(Args...)>> : func_kind_info<R(*)(Args...)> {};
 
 template <typename C, typename R, typename... Args>
 struct func_kind_info<R (C::*)(Args...) const>
     : func_kind_info<R (*)(Args...)> {};
 
-template <typename R, typename... Args> struct func_kind_info<R (*)(ftl::net::Peer &,Args...)> {
+template <typename R, typename... Args> struct func_kind_info<R (*)(ftl::net::Peer &, Args...)> {
     typedef typename tags::arg_count_trait<sizeof...(Args)>::type args_kind;
     typedef typename tags::result_trait<R>::type result_kind;
-	typedef true_ has_peer;
+    typedef true_ has_peer;
 };
 
 template <typename R, typename... Args> struct func_kind_info<R (*)(Args...)> {
     typedef typename tags::arg_count_trait<sizeof...(Args)>::type args_kind;
     typedef typename tags::result_trait<R>::type result_kind;
-	typedef false_ has_peer;
+    typedef false_ has_peer;
 };
 
 template <typename F> using is_zero_arg = is_zero<func_traits<F>::arg_count>;
@@ -111,8 +119,7 @@ using is_single_arg =
 
 template <typename F>
 using is_void_result = std::is_void<typename func_traits<F>::result_type>;
-}
-}
+}  // namespace internal
+}  // namespace ftl
 
 #endif /* end of include guard: FUNC_TRAITS_H_HWIWA6G0 */
-
diff --git a/src/handlers.hpp b/src/handlers.hpp
index c8fad23a27166cf696206ef981e6d8e4b9f720b4..7c55dcac3ef85cea4ffa70f8b19937ed7892c13f 100644
--- a/src/handlers.hpp
+++ b/src/handlers.hpp
@@ -8,6 +8,7 @@
 
 #include <functional>
 #include <memory>
+#include <string>
 
 namespace ftl {
 namespace net {
@@ -24,6 +25,5 @@ using ErrorHandler = std::function<void(std::shared_ptr<Socket>, int)>;
 using ConnectHandler = std::function<void(std::shared_ptr<Socket> &)>;
 using DisconnectHandler = std::function<void(std::shared_ptr<Socket>)>;
 
-};
-};
-
+}  // namespace net
+}  // namespace ftl
diff --git a/src/node.cpp b/src/node.cpp
index 445a5041809f7e82b575dfc4c6f0be158f6d6428..1aa9d11ded10b9e013700861f34b5224a7caa349 100644
--- a/src/node.cpp
+++ b/src/node.cpp
@@ -1,3 +1,9 @@
+/**
+ * @file node.cpp
+ * @copyright Copyright (c) 2020 University of Turku, MIT License
+ * @author Nicolas Pope
+ */
+
 #include <ftl/protocol/node.hpp>
 #include "peer.hpp"
 
diff --git a/src/peer.cpp b/src/peer.cpp
index efe0af6af772c4b04deed22ec3ca7aaf635bb25c..040f7090d1582a3063e1a916ac49c81406387847 100644
--- a/src/peer.cpp
+++ b/src/peer.cpp
@@ -4,6 +4,15 @@
  * @author Nicolas Pope
  */
 
+#include <iostream>
+#include <memory>
+#include <algorithm>
+#include <tuple>
+#include <chrono>
+#include <vector>
+#include <utility>
+#include <string>
+
 #include <ftl/lib/loguru.hpp>
 #include <ftl/lib/ctpl_stl.hpp>
 
@@ -12,7 +21,6 @@
 #include <ftl/uri.hpp>
 #include <ftl/time.hpp>
 #include "peer.hpp"
-//#include <ftl/config.h>
 
 #include "protocol/connection.hpp"
 
@@ -20,13 +28,6 @@ using ftl::net::internal::SocketConnection;
 
 #include "universe.hpp"
 
-#include <iostream>
-#include <memory>
-#include <algorithm>
-#include <tuple>
-#include <chrono>
-#include <vector>
-
 using std::tuple;
 using std::get;
 using ftl::net::Peer;
@@ -39,545 +40,533 @@ using ftl::net::Callback;
 using std::vector;
 using ftl::protocol::NodeStatus;
 using ftl::protocol::NodeType;
+using ftl::protocol::Error;
 
 std::atomic_int Peer::rpcid__ = 0;
 
 int Peer::_socket() const {
-	if (sock_->is_valid()) {
-		return sock_->fd();
-	} else {
-		return INVALID_SOCKET;
-	}
+    if (sock_->is_valid()) {
+        return sock_->fd();
+    } else {
+        return INVALID_SOCKET;
+    }
 }
 
 bool Peer::isConnected() const {
-	return sock_->is_valid() && (status_ == NodeStatus::kConnected);
+    return sock_->is_valid() && (status_ == NodeStatus::kConnected);
 }
 
 bool Peer::isValid() const {
-	return sock_ && sock_->is_valid() && ((status_ == NodeStatus::kConnected) || (status_ == NodeStatus::kConnecting));
+    return sock_ && sock_->is_valid() && ((status_ == NodeStatus::kConnected) || (status_ == NodeStatus::kConnecting));
 }
 
 void Peer::_set_socket_options() {
-	CHECK(net_);
-	CHECK(sock_);
-	
-	// error printed by set methods (return value ignored)
-	sock_->set_send_buffer_size(net_->getSendBufferSize(sock_->scheme()));
-	sock_->set_recv_buffer_size(net_->getRecvBufferSize(sock_->scheme()));
-
-	DLOG(1)	<< "send buffer size: " << (sock_->get_send_buffer_size() >> 10) << "KiB, "
-			<< "recv buffer size: " << (sock_->get_recv_buffer_size() >> 10) << "KiB";
+    CHECK(net_);
+    CHECK(sock_);
+
+    // error printed by set methods (return value ignored)
+    sock_->set_send_buffer_size(net_->getSendBufferSize(sock_->scheme()));
+    sock_->set_recv_buffer_size(net_->getRecvBufferSize(sock_->scheme()));
+
+    DLOG(1) << "send buffer size: " << (sock_->get_send_buffer_size() >> 10) << "KiB, "
+            << "recv buffer size: " << (sock_->get_recv_buffer_size() >> 10) << "KiB";
 }
 
 void Peer::_send_handshake() {
-	DLOG(INFO)	<< "(" << (outgoing_ ? "connecting" : "listening")
-			<< " peer) handshake sent, status: "
-			<< (isConnected() ? "connected" : "connecting");
-	
-	send("__handshake__", ftl::net::kMagic, ftl::net::kVersion, net_->id());
+    DLOG(INFO) << "(" << (outgoing_ ? "connecting" : "listening")
+            << " peer) handshake sent, status: "
+            << (isConnected() ? "connected" : "connecting");
+
+    send("__handshake__", ftl::net::kMagic, ftl::net::kVersion, net_->id());
 }
 
-void Peer::_process_handshake(uint64_t magic, uint32_t version, UUID pid) {
-	/** Handshake protocol:
-	 * 	(1). Listening side accepts connection and sends handshake.
-	 * 	(2). Connecting side acknowledges by replying with own handshake and
-	 * 		 sets status to kConnected.
-	 * 	(3). Listening side receives handshake and sets status to kConnected.
-	 */
-	if (magic != ftl::net::kMagic) {
-		net_->_notifyError(this, ftl::protocol::Error::kBadHandshake, "invalid magic during handshake");
-		_close(reconnect_on_protocol_error_);
-	} else {
-		if (version != ftl::net::kVersion) LOG(WARNING) << "net protocol using different versions!";
-
-		DLOG(INFO) << "(" << (outgoing_ ? "connecting" : "listening")
-				  << " peer) handshake received from remote for " << pid.to_string();
-
-		status_ = NodeStatus::kConnected;
-		version_ = version;
-		peerid_ = pid;
-
-		if (outgoing_) {
-			// only outgoing connection replies with handshake, listening socket
-			// sends initial handshake on connect
-			_send_handshake();
-		}
-
-		++connection_count_;
-		net_->_notifyConnect(this);
-	}
+void Peer::_process_handshake(uint64_t magic, uint32_t version, const UUID &pid) {
+    /** Handshake protocol:
+     * 	(1). Listening side accepts connection and sends handshake.
+     * 	(2). Connecting side acknowledges by replying with own handshake and
+     * 		 sets status to kConnected.
+     * 	(3). Listening side receives handshake and sets status to kConnected.
+     */
+    if (magic != ftl::net::kMagic) {
+        net_->_notifyError(this, ftl::protocol::Error::kBadHandshake, "invalid magic during handshake");
+        _close(reconnect_on_protocol_error_);
+    } else {
+        if (version != ftl::net::kVersion) LOG(WARNING) << "net protocol using different versions!";
+
+        DLOG(INFO) << "(" << (outgoing_ ? "connecting" : "listening")
+                  << " peer) handshake received from remote for " << pid.to_string();
+
+        status_ = NodeStatus::kConnected;
+        version_ = version;
+        peerid_ = pid;
+
+        if (outgoing_) {
+            // only outgoing connection replies with handshake, listening socket
+            // sends initial handshake on connect
+            _send_handshake();
+        }
+
+        ++connection_count_;
+        net_->_notifyConnect(this);
+    }
 }
 
 void Peer::_bind_rpc() {
-	// Install return handshake handler.
-	bind("__handshake__", [this](uint64_t magic, uint32_t version, UUID pid) {
-		_process_handshake(magic, version, pid);
-	});
-
-	bind("__disconnect__", [this]() {
-		close(reconnect_on_remote_disconnect_);
-		DLOG(1) << "peer elected to disconnect: " << id().to_string();
-	});
-
-	bind("__ping__", [this]() {
-		return ftl::time::get_time();
-	});
-
+    // Install return handshake handler.
+    bind("__handshake__", [this](uint64_t magic, uint32_t version, const UUID &pid) {
+        _process_handshake(magic, version, pid);
+    });
+
+    bind("__disconnect__", [this]() {
+        close(reconnect_on_remote_disconnect_);
+        DLOG(1) << "peer elected to disconnect: " << id().to_string();
+    });
+
+    bind("__ping__", [this]() {
+        return ftl::time::get_time();
+    });
 }
 
 Peer::Peer(std::unique_ptr<internal::SocketConnection> s, Universe* u, Dispatcher* d) :
-		outgoing_(false),
-		local_id_(0),
-		uri_("0"),
-		status_(NodeStatus::kConnecting),
-		can_reconnect_(false),
-		net_(u),
-		sock_(std::move(s)),
-		disp_(std::make_unique<Dispatcher>(d)) {
-	
-	/* Incoming connection constructor */
-
-	CHECK(sock_) << "incoming SocketConnection pointer null";
-	_set_socket_options();
-	_updateURI();
-	_bind_rpc();
-	++net_->peer_instances_;
+        outgoing_(false),
+        local_id_(0),
+        uri_("0"),
+        status_(NodeStatus::kConnecting),
+        can_reconnect_(false),
+        net_(u),
+        sock_(std::move(s)),
+        disp_(std::make_unique<Dispatcher>(d)) {
+    /* Incoming connection constructor */
+
+    CHECK(sock_) << "incoming SocketConnection pointer null";
+    _set_socket_options();
+    _updateURI();
+    _bind_rpc();
+    ++net_->peer_instances_;
 }
 
-Peer::Peer(const ftl::URI& uri, Universe *u, Dispatcher *d) : 
-		outgoing_(true),
-		local_id_(0),
-		uri_(uri),
-		status_(NodeStatus::kInvalid),
-		can_reconnect_(true),
-		net_(u),
-		disp_(std::make_unique<Dispatcher>(d)) {
-	
-	/* Outgoing connection constructor */
-
-	_bind_rpc();
-	_connect();
-	++net_->peer_instances_;
+Peer::Peer(const ftl::URI& uri, Universe *u, Dispatcher *d) :
+        outgoing_(true),
+        local_id_(0),
+        uri_(uri),
+        status_(NodeStatus::kInvalid),
+        can_reconnect_(true),
+        net_(u),
+        disp_(std::make_unique<Dispatcher>(d)) {
+    /* Outgoing connection constructor */
+
+    _bind_rpc();
+    _connect();
+    ++net_->peer_instances_;
 }
 
 void Peer::start() {
-	if (outgoing_) {
-		// Connect needs to be in constructor
-	} else {
-		_send_handshake();
-	}
+    if (outgoing_) {
+        // Connect needs to be in constructor
+    } else {
+        _send_handshake();
+    }
 }
 
 void Peer::_connect() {
-	sock_ = ftl::net::internal::createConnection(uri_); // throws on bad uri
-	_set_socket_options();
-	sock_->connect(uri_); // throws on error
-	status_ = NodeStatus::kConnecting;
+    sock_ = ftl::net::internal::createConnection(uri_);  // throws on bad uri
+    _set_socket_options();
+    sock_->connect(uri_);  // throws on error
+    status_ = NodeStatus::kConnecting;
 }
 
 /** Called from ftl::Universe::_periodic() */
 bool Peer::reconnect() {
+    if (status_ != NodeStatus::kConnecting || !can_reconnect_) return false;
 
-	if (status_ != NodeStatus::kConnecting || !can_reconnect_) return false;
-
-	URI uri(uri_);
+    URI uri(uri_);
 
-	DLOG(INFO) << "Reconnecting to " << uri_.to_string() << " ...";
+    DLOG(INFO) << "Reconnecting to " << uri_.to_string() << " ...";
 
-	// First, ensure all stale jobs and buffer data are removed.
-	while (job_count_ > 0 && ftl::pool.size() > 0) {
-		DLOG(1) << "Waiting on peer jobs before reconnect " << job_count_;
-		std::this_thread::sleep_for(std::chrono::milliseconds(2));
-	}
-	recv_buf_.remove_nonparsed_buffer();
-	recv_buf_.reset();
+    // First, ensure all stale jobs and buffer data are removed.
+    while (job_count_ > 0 && ftl::pool.size() > 0) {
+        DLOG(1) << "Waiting on peer jobs before reconnect " << job_count_;
+        std::this_thread::sleep_for(std::chrono::milliseconds(2));
+    }
+    recv_buf_.remove_nonparsed_buffer();
+    recv_buf_.reset();
 
-	try {
-		_connect();
-		return true;
-		
-	} catch(const std::exception& ex) {
-		net_->_notifyError(this, ftl::protocol::Error::kReconnectionFailed, ex.what());
-	}
+    try {
+        _connect();
+        return true;
+    } catch(const std::exception& ex) {
+        net_->_notifyError(this, ftl::protocol::Error::kReconnectionFailed, ex.what());
+    }
 
-	close(true); 
-	return false;
+    close(true);
+    return false;
 }
 
 void Peer::_updateURI() {
-	// should be same as provided uri for connecting sockets, for connections
-	// created by listening socket should generate some meaningful value
-	uri_ = sock_->uri();
+    // should be same as provided uri for connecting sockets, for connections
+    // created by listening socket should generate some meaningful value
+    uri_ = sock_->uri();
 }
 
-void Peer::rawClose() {	
-	UNIQUE_LOCK(send_mtx_, lk_send);
-	//UNIQUE_LOCK(recv_mtx_, lk_recv);
-	sock_->close();
-	status_ = NodeStatus::kDisconnected;
+void Peer::rawClose() {
+    UNIQUE_LOCK(send_mtx_, lk_send);
+    // UNIQUE_LOCK(recv_mtx_, lk_recv);
+    sock_->close();
+    status_ = NodeStatus::kDisconnected;
 }
 
 void Peer::close(bool retry) {
-	// Attempt to inform about disconnect
-	if (sock_->is_valid() && status_ == NodeStatus::kConnected) {
-		send("__disconnect__");
-	}
+    // Attempt to inform about disconnect
+    if (sock_->is_valid() && status_ == NodeStatus::kConnected) {
+        send("__disconnect__");
+    }
 
-	UNIQUE_LOCK(send_mtx_, lk_send);
-	//UNIQUE_LOCK(recv_mtx_, lk_recv);
+    UNIQUE_LOCK(send_mtx_, lk_send);
+    // UNIQUE_LOCK(recv_mtx_, lk_recv);
 
-	_close(retry);
+    _close(retry);
 }
 
 void Peer::_close(bool retry) {
-	if (status_ != NodeStatus::kConnected && status_ != NodeStatus::kConnecting) return;
-	
-	// Attempt auto reconnect?
-	if (retry && can_reconnect_) {
-		status_ = NodeStatus::kReconnecting;
-	} else {
-		status_ = NodeStatus::kDisconnected;
-	}
-
-	if (sock_->is_valid()) {
-		net_->_notifyDisconnect(this);
-		sock_->close();
-	}
+    if (status_ != NodeStatus::kConnected && status_ != NodeStatus::kConnecting) return;
+
+    // Attempt auto reconnect?
+    if (retry && can_reconnect_) {
+        status_ = NodeStatus::kReconnecting;
+    } else {
+        status_ = NodeStatus::kDisconnected;
+    }
+
+    if (sock_->is_valid()) {
+        net_->_notifyDisconnect(this);
+        sock_->close();
+    }
 }
 
 bool Peer::socketError() {
-	int errcode = sock_->getSocketError();
+    int errcode = sock_->getSocketError();
 
-	if (!sock_->is_fatal(errcode)) return false;
+    if (!sock_->is_fatal(errcode)) return false;
 
-	if (errcode == ECONNRESET) {
-		_close(reconnect_on_socket_error_);
-		return true;
-	}
+    if (errcode == ECONNRESET) {
+        _close(reconnect_on_socket_error_);
+        return true;
+    }
 
-	net_->_notifyError(this, ftl::protocol::Error::kSocketError, std::string("Socket error: ") + std::to_string(errcode));
-	_close(reconnect_on_socket_error_); 
-	return true;
+    net_->_notifyError(this, Error::kSocketError, std::string("Socket error: ") + std::to_string(errcode));
+    _close(reconnect_on_socket_error_);
+    return true;
 }
 
-void Peer::error(int e) {
-	
-}
+void Peer::error(int e) {}
 
 NodeType Peer::getType() const {
-	if ((uri_.getScheme() == URI::SCHEME_WS)
-		|| (uri_.getScheme() == URI::SCHEME_WSS)) {
-		
-		return NodeType::kWebService;
-	}
-	return NodeType::kNode;
+    if ((uri_.getScheme() == URI::SCHEME_WS)
+        || (uri_.getScheme() == URI::SCHEME_WSS)) {
+        return NodeType::kWebService;
+    }
+    return NodeType::kNode;
 }
 
 void Peer::_createJob() {
-	++job_count_;
-
-	ftl::pool.push([this](int id) {
-		try {
-			_data();
-		} catch (const std::exception &e) {
-			net_->_notifyError(this, ftl::protocol::Error::kUnknown, e.what());	
-		}
-		--job_count_;
-	});
+    ++job_count_;
+
+    ftl::pool.push([this](int id) {
+        try {
+            _data();
+        } catch (const std::exception &e) {
+            net_->_notifyError(this, ftl::protocol::Error::kUnknown, e.what());
+        }
+        --job_count_;
+    });
 }
 
 void Peer::data() {
-	if (!sock_->is_valid()) { return; }
-
-	int rc = 0;
-
-	// Only need to lock and reserve buffer if there isn't enough
-	if (recv_buf_.buffer_capacity() < kMaxMessage) {
-		UNIQUE_LOCK(recv_mtx_,lk);
-		recv_buf_.reserve_buffer(kMaxMessage);
-	}
-
-	int cap = static_cast<int>(recv_buf_.buffer_capacity());
-
-	try {
-		rc = sock_->recv(recv_buf_.buffer(), recv_buf_.buffer_capacity());
-		
-		if (rc >= cap - 1) {
-			net_->_notifyError(this, ftl::protocol::Error::kBufferSize, "Too much data received"); 
-			// TODO: Increase the buffer size next time
-		}
-		if (cap < (kMaxMessage / 10)) {
-			net_->_notifyError(this, ftl::protocol::Error::kBufferSize, "Buffer is at capacity"); 
-		}
-
-	} catch (std::exception& ex) {
-		net_->_notifyError(this, ftl::protocol::Error::kSocketError, ex.what());	
-		close(reconnect_on_socket_error_);
-		return;
-
-	}
-
-	if (rc == 0) { // retry later
-		CHECK(sock_->is_valid() == false);
-		//close(reconnect_on_socket_error_);
-		return;
-	}
-	if (rc < 0) { // error so close peer
-		sock_->close();
-		close(reconnect_on_socket_error_);
-		return;
-	}
-
-	// May possibly need locking
-	recv_buf_.buffer_consumed(rc);
-
-	recv_checked_.clear();
-	if (!already_processing_.test_and_set()) {
-		//lk.unlock();
-		_createJob();
-	}
+    if (!sock_->is_valid()) { return; }
+
+    int rc = 0;
+
+    // Only need to lock and reserve buffer if there isn't enough
+    if (recv_buf_.buffer_capacity() < kMaxMessage) {
+        UNIQUE_LOCK(recv_mtx_, lk);
+        recv_buf_.reserve_buffer(kMaxMessage);
+    }
+
+    int cap = static_cast<int>(recv_buf_.buffer_capacity());
+
+    try {
+        rc = sock_->recv(recv_buf_.buffer(), recv_buf_.buffer_capacity());
+
+        if (rc >= cap - 1) {
+            net_->_notifyError(this, Error::kBufferSize, "Too much data received");
+            // TODO(Nick): Increase the buffer size next time
+        }
+        if (cap < (kMaxMessage / 10)) {
+            net_->_notifyError(this, Error::kBufferSize, "Buffer is at capacity");
+        }
+    } catch (std::exception& ex) {
+        net_->_notifyError(this, Error::kSocketError, ex.what());
+        close(reconnect_on_socket_error_);
+        return;
+    }
+
+    if (rc == 0) {  // retry later
+        CHECK(sock_->is_valid() == false);
+        // close(reconnect_on_socket_error_);
+        return;
+    }
+    if (rc < 0) {  // error so close peer
+        sock_->close();
+        close(reconnect_on_socket_error_);
+        return;
+    }
+
+    // May possibly need locking
+    recv_buf_.buffer_consumed(rc);
+
+    recv_checked_.clear();
+    if (!already_processing_.test_and_set()) {
+        // lk.unlock();
+        _createJob();
+    }
 }
 
 bool Peer::_has_next() {
+    if (!sock_->is_valid()) { return false; }
 
-	if (!sock_->is_valid()) { return false; }
-
-	bool has_next = true;
-	// buffer might contain non-msgpack data (headers etc). check with
-	// prepare_next() and skip if necessary
-	size_t skip;
-	auto buffer = recv_buf_.nonparsed_buffer();
-	auto buffer_len = recv_buf_.nonparsed_size();
-	has_next = sock_->prepare_next(buffer, buffer_len, skip);
+    bool has_next = true;
+    // buffer might contain non-msgpack data (headers etc). check with
+    // prepare_next() and skip if necessary
+    size_t skip;
+    auto buffer = recv_buf_.nonparsed_buffer();
+    auto buffer_len = recv_buf_.nonparsed_size();
+    has_next = sock_->prepare_next(buffer, buffer_len, skip);
 
-	if (has_next) { recv_buf_.skip_nonparsed_buffer(skip); }
+    if (has_next) { recv_buf_.skip_nonparsed_buffer(skip); }
 
-	return has_next;
+    return has_next;
 }
 
 bool Peer::_data() {
-	// lock before trying to acquire handle to buffer
-	//UNIQUE_LOCK(recv_mtx_, lk);
-
-	// msgpack::object is valid as long as handle is
-	msgpack::object_handle msg_handle;
-
-	try {
-		recv_checked_.test_and_set();
-
-		UNIQUE_LOCK(recv_mtx_,lk);
-		bool has_next = _has_next() && recv_buf_.next(msg_handle);
-		lk.unlock();
-
-		if (!has_next) {
-			already_processing_.clear();
-			if (!recv_checked_.test_and_set() && !already_processing_.test_and_set()) {
-				return _data();
-			}
-			return false;
-		}
-	} catch (const std::exception& ex) {
-		net_->_notifyError(this, ftl::protocol::Error::kPacketFailure, ex.what());
-		_close(reconnect_on_protocol_error_);
-		return false;
-	}
-
-	//lk.unlock();
-
-	msgpack::object obj = msg_handle.get();
-
-	if (status_ == NodeStatus::kConnecting) {
-		// If not connected, must lock to make sure no other thread performs this step
-		//lk.lock();
-
-		// Verify still not connected after lock
-		//if (status_ == NodeStatus::kConnecting) {
-			// First message must be a handshake
-			try {
-				tuple<uint32_t, std::string, msgpack::object> hs;
-				obj.convert(hs);
-				
-				if (get<1>(hs) != "__handshake__") {
-					DLOG(WARNING) << "Missing handshake - got '" << get<1>(hs) << "'";
-
-					// Allow a small delay in case another thread is doing the handshake
-					//lk.unlock();
-					std::this_thread::sleep_for(std::chrono::milliseconds(10));
-					if (status_ == NodeStatus::kConnecting) {
-						net_->_notifyError(this, ftl::protocol::Error::kMissingHandshake, "failed to get handshake");
-						close(reconnect_on_protocol_error_);
-						//lk.lock();
-						return false;
-					}
-				} else {
-					// Must handle immediately with no other thread able
-					// to read next message before completion.
-					// The handshake handler must not block.
-
-					try {
-						disp_->dispatch(*this, obj);
-					} catch (const std::exception &e) {
-						net_->_notifyError(this, ftl::protocol::Error::kDispatchFailed, e.what());
-					}
-
-					_createJob();
-					return true;
-				}
-			} catch(...) {
-				DLOG(WARNING) << "Bad first message format... waiting";
-				// Allow a small delay in case another thread is doing the handshake
-
-				//lk.unlock();
-				std::this_thread::sleep_for(std::chrono::milliseconds(10));
-				if (status_ == NodeStatus::kConnecting) {
-					net_->_notifyError(this, ftl::protocol::Error::kMissingHandshake, "failed to get handshake");
-					close(reconnect_on_protocol_error_);
-					return false;
-				}
-			}
-		//} else {
-			//lk.unlock();
-		//}
-	}
-	
-	// Process more data...
-	_createJob();
-	
-	try {
-		disp_->dispatch(*this, obj);
-	} catch (const std::exception &e) {
-		net_->_notifyError(this, ftl::protocol::Error::kDispatchFailed, e.what());
-	}
-
-	// Lock again before freeing msg_handle (destruction order).
-	// msgpack::object_handle destructor modifies recv_buffer_
-	//lk.lock();
-	return true;
+    // lock before trying to acquire handle to buffer
+    // UNIQUE_LOCK(recv_mtx_, lk);
+
+    // msgpack::object is valid as long as handle is
+    msgpack::object_handle msg_handle;
+
+    try {
+        recv_checked_.test_and_set();
+
+        UNIQUE_LOCK(recv_mtx_, lk);
+        bool has_next = _has_next() && recv_buf_.next(msg_handle);
+        lk.unlock();
+
+        if (!has_next) {
+            already_processing_.clear();
+            if (!recv_checked_.test_and_set() && !already_processing_.test_and_set()) {
+                return _data();
+            }
+            return false;
+        }
+    } catch (const std::exception& ex) {
+        net_->_notifyError(this, ftl::protocol::Error::kPacketFailure, ex.what());
+        _close(reconnect_on_protocol_error_);
+        return false;
+    }
+
+    // lk.unlock();
+
+    msgpack::object obj = msg_handle.get();
+
+    if (status_ == NodeStatus::kConnecting) {
+        // If not connected, must lock to make sure no other thread performs this step
+        // lk.lock();
+
+        // Verify still not connected after lock
+        // if (status_ == NodeStatus::kConnecting) {
+            // First message must be a handshake
+            try {
+                tuple<uint32_t, std::string, msgpack::object> hs;
+                obj.convert(hs);
+
+                if (get<1>(hs) != "__handshake__") {
+                    DLOG(WARNING) << "Missing handshake - got '" << get<1>(hs) << "'";
+
+                    // Allow a small delay in case another thread is doing the handshake
+                    // lk.unlock();
+                    std::this_thread::sleep_for(std::chrono::milliseconds(10));
+                    if (status_ == NodeStatus::kConnecting) {
+                        net_->_notifyError(this, Error::kMissingHandshake, "failed to get handshake");
+                        close(reconnect_on_protocol_error_);
+                        // lk.lock();
+                        return false;
+                    }
+                } else {
+                    // Must handle immediately with no other thread able
+                    // to read next message before completion.
+                    // The handshake handler must not block.
+
+                    try {
+                        disp_->dispatch(*this, obj);
+                    } catch (const std::exception &e) {
+                        net_->_notifyError(this, ftl::protocol::Error::kDispatchFailed, e.what());
+                    }
+
+                    _createJob();
+                    return true;
+                }
+            } catch(...) {
+                DLOG(WARNING) << "Bad first message format... waiting";
+                // Allow a small delay in case another thread is doing the handshake
+
+                // lk.unlock();
+                std::this_thread::sleep_for(std::chrono::milliseconds(10));
+                if (status_ == NodeStatus::kConnecting) {
+                    net_->_notifyError(this, Error::kMissingHandshake, "failed to get handshake");
+                    close(reconnect_on_protocol_error_);
+                    return false;
+                }
+            }
+        // } else {
+            // lk.unlock();
+        // }
+    }
+
+    // Process more data...
+    _createJob();
+
+    try {
+        disp_->dispatch(*this, obj);
+    } catch (const std::exception &e) {
+        net_->_notifyError(this, Error::kDispatchFailed, e.what());
+    }
+
+    // Lock again before freeing msg_handle (destruction order).
+    // msgpack::object_handle destructor modifies recv_buffer_
+    // lk.lock();
+    return true;
 }
 
 void Peer::_dispatchResponse(uint32_t id, const std::string &name, msgpack::object &res) {
-	UNIQUE_LOCK(cb_mtx_,lk);
-	if (callbacks_.count(id) > 0) {
-		
-		// Allow for unlock before callback
-		auto cb = std::move(callbacks_[id]);
-		callbacks_.erase(id);
-		lk.unlock();
-
-		// Call the callback with unpacked return value
-		try {
-			(*cb)(res);
-		} catch(std::exception &e) {
-			net_->_notifyError(this, ftl::protocol::Error::kRPCResponse, e.what());	
-		}
-	} else {
-		net_->_notifyError(this, ftl::protocol::Error::kRPCResponse, "Missing RPC callback for result - discarding: " + name);	
-	}
+    UNIQUE_LOCK(cb_mtx_, lk);
+    if (callbacks_.count(id) > 0) {
+        // Allow for unlock before callback
+        auto cb = std::move(callbacks_[id]);
+        callbacks_.erase(id);
+        lk.unlock();
+
+        // Call the callback with unpacked return value
+        try {
+            (*cb)(res);
+        } catch(std::exception &e) {
+            net_->_notifyError(this, Error::kRPCResponse, e.what());
+        }
+    } else {
+        net_->_notifyError(this, Error::kRPCResponse, "Missing RPC callback for result - discarding: " + name);
+    }
 }
 
 void Peer::cancelCall(int id) {
-	UNIQUE_LOCK(cb_mtx_,lk);
-	if (callbacks_.count(id) > 0) {
-		callbacks_.erase(id);
-	}
+    UNIQUE_LOCK(cb_mtx_, lk);
+    if (callbacks_.count(id) > 0) {
+        callbacks_.erase(id);
+    }
 }
 
 void Peer::_sendResponse(uint32_t id, const std::string &name, const msgpack::object &res) {
-	Dispatcher::response_t res_obj = std::make_tuple(1,id,name,res);
-	UNIQUE_LOCK(send_mtx_,lk);
-	msgpack::pack(send_buf_, res_obj);
-	_send();
+    Dispatcher::response_t res_obj = std::make_tuple(1, id, name, res);
+    UNIQUE_LOCK(send_mtx_, lk);
+    msgpack::pack(send_buf_, res_obj);
+    _send();
 }
 
 void Peer::_waitCall(int id, std::condition_variable &cv, bool &hasreturned, const std::string &name) {
-	std::mutex m;
-
-	int64_t beginat = ftl::time::get_time();
-	std::function<void(int)> j;
-	while (!hasreturned) {
-		// Attempt to do a thread pool job if available
-		if ((bool)(j=ftl::pool.pop())) {
-			j(-1);
-		} else {
-			// Block for a little otherwise
-			std::unique_lock<std::mutex> lk(m);
-			cv.wait_for(lk, std::chrono::milliseconds(2), [&hasreturned]{return hasreturned;});
-		}
-
-		if (ftl::time::get_time() - beginat > 1000) break;
-	}
-	
-	if (!hasreturned) {
-		cancelCall(id);
-		throw FTL_Error("RPC failed with timeout: " << name);
-	}
+    std::mutex m;
+
+    int64_t beginat = ftl::time::get_time();
+    std::function<void(int)> j;
+    while (!hasreturned) {
+        // Attempt to do a thread pool job if available
+        if (static_cast<bool>(j = ftl::pool.pop())) {
+            j(-1);
+        } else {
+            // Block for a little otherwise
+            std::unique_lock<std::mutex> lk(m);
+            cv.wait_for(lk, std::chrono::milliseconds(2), [&hasreturned]{return hasreturned;});
+        }
+
+        if (ftl::time::get_time() - beginat > 1000) break;
+    }
+
+    if (!hasreturned) {
+        cancelCall(id);
+        throw FTL_Error("RPC failed with timeout: " << name);
+    }
 }
 
 bool Peer::waitConnection(int s) {
-	if (status_ == NodeStatus::kConnected) return true;
-	else if (status_ == NodeStatus::kDisconnected) return false;
-	
-	std::mutex m;
-	m.lock();
-	std::condition_variable_any cv;
-
-	auto h = net_->onConnect([this, &cv](const PeerPtr &p) {
-		if (p.get() == this) {
-			cv.notify_one();
-		}
-		return true;
-	});
-
-	cv.wait_for(m, seconds(s), [this]() { return status_ == NodeStatus::kConnected;});
-	m.unlock();
-	return status_ == NodeStatus::kConnected;
+    if (status_ == NodeStatus::kConnected) return true;
+    else if (status_ == NodeStatus::kDisconnected) return false;
+
+    std::mutex m;
+    m.lock();
+    std::condition_variable_any cv;
+
+    auto h = net_->onConnect([this, &cv](const PeerPtr &p) {
+        if (p.get() == this) {
+            cv.notify_one();
+        }
+        return true;
+    });
+
+    cv.wait_for(m, seconds(s), [this]() { return status_ == NodeStatus::kConnected;});
+    m.unlock();
+    return status_ == NodeStatus::kConnected;
 }
 
 int Peer::_send() {
-	if (!sock_->is_valid()) return -1;
-
-	ssize_t c = 0;
-	
-	try {
-		c = sock_->writev(send_buf_.vector(), send_buf_.vector_size());
-		if (c <= 0) {
-			// writev() should probably throw exception which is reported here
-			// at the moment, error message is (should be) printed by writev()
-			net_->_notifyError(this, ftl::protocol::Error::kSocketError, "writev() failed");
-			return c;
-		}
-	
-		ssize_t sz = 0; for (size_t i = 0; i < send_buf_.vector_size(); i++) {
-			sz += send_buf_.vector()[i].iov_len;
-		} 
-		if (c != sz) {
-			net_->_notifyError(this, ftl::protocol::Error::kSocketError, "writev(): incomplete send");
-			_close(reconnect_on_socket_error_);
-		}
-
-		send_buf_.clear();
-
-	} catch (std::exception& ex) {
-		net_->_notifyError(this, ftl::protocol::Error::kSocketError, ex.what());
-		_close(reconnect_on_socket_error_);
-	}
-	
-	return c;
+    if (!sock_->is_valid()) return -1;
+
+    ssize_t c = 0;
+
+    try {
+        c = sock_->writev(send_buf_.vector(), send_buf_.vector_size());
+        if (c <= 0) {
+            // writev() should probably throw exception which is reported here
+            // at the moment, error message is (should be) printed by writev()
+            net_->_notifyError(this, ftl::protocol::Error::kSocketError, "writev() failed");
+            return c;
+        }
+
+        ssize_t sz = 0; for (size_t i = 0; i < send_buf_.vector_size(); i++) {
+            sz += send_buf_.vector()[i].iov_len;
+        }
+        if (c != sz) {
+            net_->_notifyError(this, ftl::protocol::Error::kSocketError, "writev(): incomplete send");
+            _close(reconnect_on_socket_error_);
+        }
+
+        send_buf_.clear();
+    } catch (std::exception& ex) {
+        net_->_notifyError(this, ftl::protocol::Error::kSocketError, ex.what());
+        _close(reconnect_on_socket_error_);
+    }
+
+    return c;
 }
 
 Peer::~Peer() {
-	--net_->peer_instances_;
-	{
-		UNIQUE_LOCK(send_mtx_,lk1);
-		//UNIQUE_LOCK(recv_mtx_,lk2);
-		_close(false);
-	}
-
-	// Prevent deletion if there are any jobs remaining
-	if (job_count_ > 0 && ftl::pool.size() > 0) {
-		DLOG(1) << "Waiting on peer jobs... " << job_count_;
-		std::this_thread::sleep_for(std::chrono::milliseconds(2));
-		if (job_count_ > 0) LOG(FATAL) << "Peer jobs not terminated";
-	}
+    --net_->peer_instances_;
+    {
+        UNIQUE_LOCK(send_mtx_, lk1);
+        // UNIQUE_LOCK(recv_mtx_,lk2);
+        _close(false);
+    }
+
+    // Prevent deletion if there are any jobs remaining
+    if (job_count_ > 0 && ftl::pool.size() > 0) {
+        DLOG(1) << "Waiting on peer jobs... " << job_count_;
+        std::this_thread::sleep_for(std::chrono::milliseconds(2));
+        if (job_count_ > 0) LOG(FATAL) << "Peer jobs not terminated";
+    }
 }
diff --git a/src/peer.hpp b/src/peer.hpp
index df7bae20238d3a96a5ba77feb5e32a3dc4d030bf..fb1a2ba283ae9f7cbe9d23f89f4201f052c53664 100644
--- a/src/peer.hpp
+++ b/src/peer.hpp
@@ -10,6 +10,17 @@
 #define NOMINMAX
 #endif
 
+#include <tuple>
+#include <vector>
+#include <type_traits>
+#include <thread>
+#include <condition_variable>
+#include <chrono>
+#include <memory>
+#include <map>
+#include <utility>
+#include <string>
+
 #include <msgpack.hpp>
 #include "common_fwd.hpp"
 #include "socket.hpp"
@@ -22,14 +33,6 @@
 #include <ftl/uuid.hpp>
 #include <ftl/threads.hpp>
 
-#include <tuple>
-#include <vector>
-#include <type_traits>
-#include <thread>
-#include <condition_variable>
-#include <chrono>
-#include <memory>
-
 
 # define ENABLE_IF(...) \
   typename std::enable_if<(__VA_ARGS__), bool>::type = true
@@ -43,14 +46,17 @@ namespace net {
 class Universe;
 
 struct virtual_caller {
-	virtual void operator()(msgpack::object &o)=0;
+    virtual void operator()(msgpack::object &o) = 0;
 };
 
 template <typename T>
 struct caller : virtual_caller {
-	explicit caller(const std::function<void(const T&)> &f) : f_(f) {};
-	void operator()(msgpack::object &o) override { T r = o.as<T>(); f_(r); };
-	std::function<void(const T&)> f_;
+    explicit caller(const std::function<void(const T&)> &f) : f_(f) {}
+    void operator()(msgpack::object &o) override {
+        T r = o.as<T>();
+        f_(r);
+    }
+    std::function<void(const T&)> f_;
 };
 
 /**
@@ -58,303 +64,306 @@ struct caller : virtual_caller {
  * created directly.
  */
 class Peer {
-	public:
-	friend class Universe;
-	friend class Dispatcher;
-
-	/** Peer for outgoing connection: resolve address and connect */
-	explicit Peer(const ftl::URI& uri, ftl::net::Universe*, ftl::net::Dispatcher* d=nullptr);
-
-	/** Peer for incoming connection: take ownership of given connection */
-	explicit Peer(std::unique_ptr<internal::SocketConnection> s, ftl::net::Universe*, ftl::net::Dispatcher* d=nullptr);
-
-	~Peer();
-
-	void start();
-	
-	/**
-	 * Close the peer if open. Setting retry parameter to true will initiate
-	 * backoff retry attempts. This is used to deliberately close a connection
-	 * and not for error conditions where different close semantics apply.
-	 * 
-	 * @param retry Should reconnection be attempted?
-	 */
-	void close(bool retry=false);
-
-	bool isConnected() const;
-	/**
-	 * Block until the connection and handshake has completed. You should use
-	 * onConnect callbacks instead of blocking, mostly this is intended for
-	 * the unit tests to keep them synchronous.
-	 * 
-	 * @return True if all connections were successful, false if timeout or error.
-	 */
-	bool waitConnection(int seconds = 1);
-
-	/**
-	 * Make a reconnect attempt. Called internally by Universe object.
-	 */
-	bool reconnect();
-
-	inline bool isOutgoing() const { return outgoing_; }
-	
-	/**
-	 * Test if the connection is valid. This returns true in all conditions
-	 * except where the socket has been disconnected permenantly, or was never
-	 * able to connect, perhaps due to an invalid address, or is in middle of a
-	 * reconnect attempt. (Valid states: kConnecting, kConnected)
-	 * 
-	 * Should return true only in cases when valid OS socket exists.
-	 */
-	bool isValid() const;
-	
-	/** peer type */
-	ftl::protocol::NodeType getType() const;
-
-	ftl::protocol::NodeStatus status() const { return status_; }
-	
-	uint32_t getFTLVersion() const { return version_; }
-	uint8_t getFTLMajor() const { return version_ >> 16; }
-	uint8_t getFTLMinor() const { return (version_ >> 8) & 0xFF; }
-	uint8_t getFTLPatch() const { return version_ & 0xFF; }
-	
-	/**
-	 * Get the sockets protocol, address and port as a url string. This will be
-	 * the same as the initial connection string on the client.
-	 */
-	std::string getURI() const { return uri_.to_string(); };
-
-	const ftl::URI &getURIObject() const { return uri_; }
-	
-	/**
-	 * Get the UUID for this peer.
-	 */
-	const ftl::UUID &id() const { return peerid_; };
-	
-	/**
-	 * Get the peer id as a string.
-	 */
-	std::string to_string() const { return peerid_.to_string(); };
-			
-	/**
-	 * Non-blocking Remote Procedure Call using a callback function.
-	 * 
-	 * @param name RPC Function name.
-	 * @param cb Completion callback.
-	 * @param args A variable number of arguments for RPC function.
-	 * 
-	 * @return A call id for use with cancelCall() if needed.
-	 */
-	template <typename T, typename... ARGS>
-	int asyncCall(const std::string &name,
-			std::function<void(const T&)> cb,
-			ARGS... args);
-
-	/**
-	 * Used to terminate an async call if the response is not required.
-	 * 
-	 * @param id The ID returned by the original asyncCall request.
-	 */
-	void cancelCall(int id);
-	
-	/**
-	 * Blocking Remote Procedure Call using a string name.
-	 */
-	template <typename R, typename... ARGS>
-	R call(const std::string &name, ARGS... args);
-	
-	/**
-	 * Non-blocking send using RPC function, but with no return value.
-	 * 
-	 * @param name RPC Function name
-	 * @param args Variable number of arguments for function
-	 * 
-	 * @return Number of bytes sent or -1 if error
-	 */
-	template <typename... ARGS>
-	int send(const std::string &name, ARGS... args);
-
-	template <typename... ARGS>
-	int try_send(const std::string &name, ARGS... args);
-	
-	/**
-	 * Bind a function to an RPC call name. Note: if an overriding dispatcher
-	 * is used then these bindings will propagate to all peers sharing that
-	 * dispatcher.
-	 * 
-	 * @param name RPC name to bind to
-	 * @param func A function object to act as callback
-	 */
-	template <typename F>
-	void bind(const std::string &name, F func);
-
-	void rawClose();
-
-	inline void noReconnect() { can_reconnect_ = false; }
-
-	inline unsigned int localID() const { return local_id_; }
-
-	int connectionCount() const { return connection_count_; }
-
-	/**
-	 * @brief Call recv to get data. Internal use, it is blocking so should only
-	 * be done if data is available.
-	 * 
-	 */
-	void data();
-	
-	public:
-	static const int kMaxMessage = 2*1024*1024;  // 10Mb currently
-	
-private: // Functions
-	bool socketError();		// Process one error from socket
-	void error(int e);
-
-	// check if buffer has enough decoded data from lower layer and advance
-	// buffer if necessary (skip headers etc).
-	bool _has_next();
-
-	// After data is read from network, _data() is called on new thread.
-	// Received data is kept valid until _data() returns 
-	// (by msgpack::object_handle in local scope).
-	bool _data();
-
-	// close socket without sending disconnect message
-	void _close(bool retry=true);
-	
-	void _dispatchResponse(uint32_t id, const std::string &name, msgpack::object &obj);
-	void _sendResponse(uint32_t id, const std::string &name, const msgpack::object &obj);
-	
-	/**
-	 * Get the internal OS dependent socket.
-	 * TODO(nick) Work out if this should be private. Used by select() in
-	 * Universe (universe.cpp)
-	 */
-	int _socket() const;
-
-	void _send_handshake();
-	void _process_handshake(uint64_t magic, uint32_t version, UUID pid);
-	
-	void _updateURI();
-	void _set_socket_options();
-	void _bind_rpc();
-
-	void _connect();
-	int _send();
-
-	void _createJob();
-
-	void _waitCall(int id, std::condition_variable &cv, bool &hasreturned, const std::string &name);
-	
-	template<typename... ARGS>
-	void _trigger(const std::vector<std::function<void(Peer &, ARGS...)>> &hs, ARGS... args) {
-		for (auto h : hs) {
-			h(*this, args...);
-		}
-	}
-
-	std::atomic_flag already_processing_ = ATOMIC_FLAG_INIT;
-	std::atomic_flag recv_checked_ = ATOMIC_FLAG_INIT;
-
-	msgpack::unpacker recv_buf_;
-	MUTEX recv_mtx_;
-	
-	// Send buffers
-	msgpack::vrefbuffer send_buf_;
-	RECURSIVE_MUTEX send_mtx_;
-
-	RECURSIVE_MUTEX cb_mtx_;
-	
-	const bool outgoing_;
-	unsigned int local_id_;
-	ftl::URI uri_;									// Original connection URI, or assumed URI
-	ftl::UUID peerid_;								// Received in handshake or allocated
-	ftl::protocol::NodeStatus status_;				// Connected, errored, reconnecting..
-	uint32_t version_;								// Received protocol version in handshake
-	bool can_reconnect_;							// Client connections can retry
-	ftl::net::Universe *net_;						// Origin net universe
-
-	std::unique_ptr<internal::SocketConnection> sock_;
-	std::unique_ptr<ftl::net::Dispatcher> disp_;	// For RPC call dispatch
-	std::map<int, std::unique_ptr<virtual_caller>> callbacks_;
-
-	std::atomic_int job_count_ = 0;					// Ensure threads are done before destructing
-	std::atomic_int connection_count_ = 0;			// Number of successful connections total
-	std::atomic_int retry_count_ = 0;				// Current number of reconnection attempts
-
-	// reconnect when clean disconnect received from remote
-	bool reconnect_on_remote_disconnect_ = true;
-	// reconnect on socket error/disconnect without message (remote crash ...)
-	bool reconnect_on_socket_error_ = true;
-	// reconnect on protocol error (msgpack decode, bad handshake, ...)
-	bool reconnect_on_protocol_error_ = false;
-
-	static std::atomic_int rpcid__;				// Return ID for RPC calls
+ public:
+    friend class Universe;
+    friend class Dispatcher;
+
+    /** Peer for outgoing connection: resolve address and connect */
+    explicit Peer(const ftl::URI& uri, ftl::net::Universe*, ftl::net::Dispatcher* d = nullptr);
+
+    /** Peer for incoming connection: take ownership of given connection */
+    explicit Peer(
+        std::unique_ptr<internal::SocketConnection> s,
+        ftl::net::Universe*,
+        ftl::net::Dispatcher* d = nullptr);
+
+    ~Peer();
+
+    void start();
+
+    /**
+     * Close the peer if open. Setting retry parameter to true will initiate
+     * backoff retry attempts. This is used to deliberately close a connection
+     * and not for error conditions where different close semantics apply.
+     * 
+     * @param retry Should reconnection be attempted?
+     */
+    void close(bool retry = false);
+
+    bool isConnected() const;
+    /**
+     * Block until the connection and handshake has completed. You should use
+     * onConnect callbacks instead of blocking, mostly this is intended for
+     * the unit tests to keep them synchronous.
+     * 
+     * @return True if all connections were successful, false if timeout or error.
+     */
+    bool waitConnection(int seconds = 1);
+
+    /**
+     * Make a reconnect attempt. Called internally by Universe object.
+     */
+    bool reconnect();
+
+    inline bool isOutgoing() const { return outgoing_; }
+
+    /**
+     * Test if the connection is valid. This returns true in all conditions
+     * except where the socket has been disconnected permenantly, or was never
+     * able to connect, perhaps due to an invalid address, or is in middle of a
+     * reconnect attempt. (Valid states: kConnecting, kConnected)
+     * 
+     * Should return true only in cases when valid OS socket exists.
+     */
+    bool isValid() const;
+
+    /** peer type */
+    ftl::protocol::NodeType getType() const;
+
+    ftl::protocol::NodeStatus status() const { return status_; }
+
+    uint32_t getFTLVersion() const { return version_; }
+    uint8_t getFTLMajor() const { return version_ >> 16; }
+    uint8_t getFTLMinor() const { return (version_ >> 8) & 0xFF; }
+    uint8_t getFTLPatch() const { return version_ & 0xFF; }
+
+    /**
+     * Get the sockets protocol, address and port as a url string. This will be
+     * the same as the initial connection string on the client.
+     */
+    std::string getURI() const { return uri_.to_string(); }
+
+    const ftl::URI &getURIObject() const { return uri_; }
+
+    /**
+     * Get the UUID for this peer.
+     */
+    const ftl::UUID &id() const { return peerid_; }
+
+    /**
+     * Get the peer id as a string.
+     */
+    std::string to_string() const { return peerid_.to_string(); }
+
+    /**
+     * Non-blocking Remote Procedure Call using a callback function.
+     * 
+     * @param name RPC Function name.
+     * @param cb Completion callback.
+     * @param args A variable number of arguments for RPC function.
+     * 
+     * @return A call id for use with cancelCall() if needed.
+     */
+    template <typename T, typename... ARGS>
+    int asyncCall(const std::string &name,
+            std::function<void(const T&)> cb,
+            ARGS... args);
+
+    /**
+     * Used to terminate an async call if the response is not required.
+     * 
+     * @param id The ID returned by the original asyncCall request.
+     */
+    void cancelCall(int id);
+
+    /**
+     * Blocking Remote Procedure Call using a string name.
+     */
+    template <typename R, typename... ARGS>
+    R call(const std::string &name, ARGS... args);
+
+    /**
+     * Non-blocking send using RPC function, but with no return value.
+     * 
+     * @param name RPC Function name
+     * @param args Variable number of arguments for function
+     * 
+     * @return Number of bytes sent or -1 if error
+     */
+    template <typename... ARGS>
+    int send(const std::string &name, ARGS&&... args);
+
+    template <typename... ARGS>
+    int try_send(const std::string &name, ARGS... args);
+
+    /**
+     * Bind a function to an RPC call name. Note: if an overriding dispatcher
+     * is used then these bindings will propagate to all peers sharing that
+     * dispatcher.
+     * 
+     * @param name RPC name to bind to
+     * @param func A function object to act as callback
+     */
+    template <typename F>
+    void bind(const std::string &name, F func);
+
+    void rawClose();
+
+    inline void noReconnect() { can_reconnect_ = false; }
+
+    inline unsigned int localID() const { return local_id_; }
+
+    int connectionCount() const { return connection_count_; }
+
+    /**
+     * @brief Call recv to get data. Internal use, it is blocking so should only
+     * be done if data is available.
+     * 
+     */
+    void data();
+
+ public:
+    static const int kMaxMessage = 2*1024*1024;  // 10Mb currently
+
+ private:  // Functions
+    bool socketError();  // Process one error from socket
+    void error(int e);
+
+    // check if buffer has enough decoded data from lower layer and advance
+    // buffer if necessary (skip headers etc).
+    bool _has_next();
+
+    // After data is read from network, _data() is called on new thread.
+    // Received data is kept valid until _data() returns
+    // (by msgpack::object_handle in local scope).
+    bool _data();
+
+    // close socket without sending disconnect message
+    void _close(bool retry = true);
+
+    void _dispatchResponse(uint32_t id, const std::string &name, msgpack::object &obj);
+    void _sendResponse(uint32_t id, const std::string &name, const msgpack::object &obj);
+
+    /**
+     * Get the internal OS dependent socket.
+     * TODO(nick) Work out if this should be private. Used by select() in
+     * Universe (universe.cpp)
+     */
+    int _socket() const;
+
+    void _send_handshake();
+    void _process_handshake(uint64_t magic, uint32_t version, const UUID &pid);
+
+    void _updateURI();
+    void _set_socket_options();
+    void _bind_rpc();
+
+    void _connect();
+    int _send();
+
+    void _createJob();
+
+    void _waitCall(int id, std::condition_variable &cv, bool &hasreturned, const std::string &name);
+
+    template<typename... ARGS>
+    void _trigger(const std::vector<std::function<void(Peer &, ARGS...)>> &hs, ARGS... args) {
+        for (auto h : hs) {
+            h(*this, args...);
+        }
+    }
+
+    std::atomic_flag already_processing_ = ATOMIC_FLAG_INIT;
+    std::atomic_flag recv_checked_ = ATOMIC_FLAG_INIT;
+
+    msgpack::unpacker recv_buf_;
+    MUTEX recv_mtx_;
+
+    // Send buffers
+    msgpack::vrefbuffer send_buf_;
+    RECURSIVE_MUTEX send_mtx_;
+
+    RECURSIVE_MUTEX cb_mtx_;
+
+    const bool outgoing_;
+    unsigned int local_id_;
+    ftl::URI uri_;                                  // Original connection URI, or assumed URI
+    ftl::UUID peerid_;                              // Received in handshake or allocated
+    ftl::protocol::NodeStatus status_;              // Connected, errored, reconnecting..
+    uint32_t version_;                              // Received protocol version in handshake
+    bool can_reconnect_;                            // Client connections can retry
+    ftl::net::Universe *net_;                       // Origin net universe
+
+    std::unique_ptr<internal::SocketConnection> sock_;
+    std::unique_ptr<ftl::net::Dispatcher> disp_;    // For RPC call dispatch
+    std::map<int, std::unique_ptr<virtual_caller>> callbacks_;
+
+    std::atomic_int job_count_ = 0;                 // Ensure threads are done before destructing
+    std::atomic_int connection_count_ = 0;          // Number of successful connections total
+    std::atomic_int retry_count_ = 0;               // Current number of reconnection attempts
+
+    // reconnect when clean disconnect received from remote
+    bool reconnect_on_remote_disconnect_ = true;
+    // reconnect on socket error/disconnect without message (remote crash ...)
+    bool reconnect_on_socket_error_ = true;
+    // reconnect on protocol error (msgpack decode, bad handshake, ...)
+    bool reconnect_on_protocol_error_ = false;
+
+    static std::atomic_int rpcid__;                 // Return ID for RPC calls
 };
 
 // --- Inline Template Implementations -----------------------------------------
 
 template <typename... ARGS>
-int Peer::send(const std::string &s, ARGS... args) {
-	UNIQUE_LOCK(send_mtx_, lk);
-	auto args_obj = std::make_tuple(args...);
-	auto call_obj = std::make_tuple(0,s,args_obj);
-	msgpack::pack(send_buf_, call_obj);
-	int rc = _send();
-	return rc;
+int Peer::send(const std::string &s, ARGS&&... args) {
+    UNIQUE_LOCK(send_mtx_, lk);
+    auto args_obj = std::make_tuple(args...);
+    auto call_obj = std::make_tuple(0, s, args_obj);
+    msgpack::pack(send_buf_, call_obj);
+    int rc = _send();
+    return rc;
 }
 
 template <typename F>
 void Peer::bind(const std::string &name, F func) {
-	disp_->bind(name, func,
-		typename ftl::internal::func_kind_info<F>::result_kind(),
-		typename ftl::internal::func_kind_info<F>::args_kind(),
-		typename ftl::internal::func_kind_info<F>::has_peer());
+    disp_->bind(name, func,
+        typename ftl::internal::func_kind_info<F>::result_kind(),
+        typename ftl::internal::func_kind_info<F>::args_kind(),
+        typename ftl::internal::func_kind_info<F>::has_peer());
 }
 
 template <typename R, typename... ARGS>
 R Peer::call(const std::string &name, ARGS... args) {
-	bool hasreturned = false;
-	std::condition_variable cv;
-	
-	R result;
-	int id = asyncCall<R>(name, [&](const R &r) {
-		result = r;
-		hasreturned = true;
-		cv.notify_one();
-	}, std::forward<ARGS>(args)...);
-	
-	_waitCall(id, cv, hasreturned, name);
-	
-	return result;
+    bool hasreturned = false;
+    std::condition_variable cv;
+
+    R result;
+    int id = asyncCall<R>(name, [&](const R &r) {
+        result = r;
+        hasreturned = true;
+        cv.notify_one();
+    }, std::forward<ARGS>(args)...);
+
+    _waitCall(id, cv, hasreturned, name);
+
+    return result;
 }
 
 template <typename T, typename... ARGS>
 int Peer::asyncCall(
-		const std::string &name,
-		// cppcheck-suppress *
-		std::function<void(const T&)> cb,
-		ARGS... args) {
-	auto args_obj = std::make_tuple(args...);
-	uint32_t rpcid = 0;
-
-	{
-		// Could this be the problem????
-		UNIQUE_LOCK(cb_mtx_,lk);
-		// Register the CB
-		rpcid = rpcid__++;
-		callbacks_[rpcid] = std::make_unique<caller<T>>(cb);
-	}
-
-	auto call_obj = std::make_tuple(0,rpcid,name,args_obj);
-	
-	UNIQUE_LOCK(send_mtx_,lk);
-	msgpack::pack(send_buf_, call_obj);
-	_send();
-	return rpcid;
+        const std::string &name,
+        // cppcheck-suppress *
+        std::function<void(const T&)> cb,
+        ARGS... args) {
+    auto args_obj = std::make_tuple(args...);
+    uint32_t rpcid = 0;
+
+    {
+        // Could this be the problem????
+        UNIQUE_LOCK(cb_mtx_, lk);
+        // Register the CB
+        rpcid = rpcid__++;
+        callbacks_[rpcid] = std::make_unique<caller<T>>(cb);
+    }
+
+    auto call_obj = std::make_tuple(0, rpcid, name, args_obj);
+
+    UNIQUE_LOCK(send_mtx_, lk);
+    msgpack::pack(send_buf_, call_obj);
+    _send();
+    return rpcid;
 }
 
 using PeerPtr = std::shared_ptr<ftl::net::Peer>;
 
-};
-};
+}  // namespace net
+}  // namespace ftl
diff --git a/src/protocol.cpp b/src/protocol.cpp
index 2a45913f94a6d88c3bf272628ad204c1002d80b0..012198d2cc9d66e177d33a0d7c48e7d8c6f6320a 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -1,3 +1,9 @@
+/**
+ * @file protocol.cpp
+ * @copyright Copyright (c) 2022 University of Turku, MIT License
+ * @author Nicolas Pope
+ */
+
 #include <ftl/protocol.hpp>
 #include <ftl/protocol/self.hpp>
 #include "universe.hpp"
@@ -5,7 +11,7 @@
 
 static std::shared_ptr<ftl::net::Universe> universe;
 
-//ctpl::thread_pool ftl::pool(std::thread::hardware_concurrency()*2);
+// ctpl::thread_pool ftl::pool(std::thread::hardware_concurrency()*2);
 ctpl::thread_pool ftl::pool(4);
 
 void ftl::protocol::reset() {
diff --git a/src/protocol.hpp b/src/protocol.hpp
index 3741af2cde53b8555ca2722754d6cc4e13e9fed5..08065448980f26013e51252134b02f973b83dc9c 100644
--- a/src/protocol.hpp
+++ b/src/protocol.hpp
@@ -8,9 +8,9 @@
 
 #pragma once
 
-#include <ftl/uuid.hpp>
 #include <ftl/protocol/config.h>
 #include <tuple>
+#include <ftl/uuid.hpp>
 
 namespace ftl {
 namespace net {
@@ -19,7 +19,7 @@ typedef std::tuple<uint64_t, uint32_t, ftl::UUID> Handshake;
 
 static const uint64_t kMagic = 0x0009340053640912;
 static const uint32_t kVersion = (FTL_VERSION_MAJOR << 16) +
-		(FTL_VERSION_MINOR << 8) + FTL_VERSION_PATCH;
+        (FTL_VERSION_MINOR << 8) + FTL_VERSION_PATCH;
 
-};
-};
+}  // namespace net
+}  // namespace ftl
diff --git a/src/protocol/connection.cpp b/src/protocol/connection.cpp
index d0e4f41b4ad422f3e0954541d46793f9f17dc9fe..deab1958aa4f68bf131396fa98da98ae76cc449c 100644
--- a/src/protocol/connection.cpp
+++ b/src/protocol/connection.cpp
@@ -1,241 +1,251 @@
+/**
+ * @file connection.cpp
+ * @copyright Copyright (c) 2022 University of Turku, MIT License
+ * @author Sebastian Hahta
+ */
+
+#include <vector>
+#include <algorithm>
+#include <string>
 #include <loguru.hpp>
-
 #include <ftl/exception.hpp>
-
 #include "connection.hpp"
 
-using namespace ftl::net::internal;
+using ftl::net::internal::SocketConnection;
+using ftl::net::internal::socket_t;
+using ftl::net::internal::SocketServer;
 using ftl::URI;
 
 // SocketConnection ////////////////////////////////////////////////////////////
 
 SocketConnection::~SocketConnection() {
-	sock_.close();
+    sock_.close();
 }
 
 socket_t SocketConnection::fd() { return sock_.fd(); }
 
 ftl::URI SocketConnection::uri() {
-	std::string str = host() + ":" + std::to_string(get_port(addr_));
-	return ftl::URI(str);
+    std::string str = host() + ":" + std::to_string(get_port(addr_));
+    return ftl::URI(str);
 }
 
 ftl::URI::scheme_t SocketConnection::scheme() const {
-	return ftl::URI::scheme_t::SCHEME_NONE;
+    return ftl::URI::scheme_t::SCHEME_NONE;
 }
 
 bool SocketConnection::is_valid() {
-	return sock_.is_open();
+    return sock_.is_open();
 }
 
 int SocketConnection::is_fatal(int code) {
-	return sock_.is_fatal(code);
+    return sock_.is_fatal(code);
 }
 
 void SocketConnection::connect(const SocketAddress &address, int timeout) {
-	addr_ = address;
-	int rv = 0;
-	if (timeout <= 0) rv = sock_.connect(addr_ );
-	else rv = sock_.connect(addr_, timeout);
-	
-	if (rv != 0) { throw FTL_Error("connect(): " + sock_.get_error_string()); }
+    addr_ = address;
+    int rv = 0;
+    if (timeout <= 0) rv = sock_.connect(addr_ );
+    else
+        rv = sock_.connect(addr_, timeout);
+
+    if (rv != 0) { throw FTL_Error("connect(): " + sock_.get_error_string()); }
 }
 
 ssize_t SocketConnection::recv(char *buffer, size_t len) {
-	auto recvd = sock_.recv(buffer, len, 0);
-	if (recvd == 0) {
-		LOG(3) << "recv(): read size 0";
-		return -1; // -1 means close, 0 means retry
-	}
-	if (recvd < 0) {
-		if (!sock_.is_fatal()) return 0;  // Retry
-		throw FTL_Error(sock_.get_error_string());
-	}
-	return recvd;
+    auto recvd = sock_.recv(buffer, len, 0);
+    if (recvd == 0) {
+        LOG(3) << "recv(): read size 0";
+        return -1;  // -1 means close, 0 means retry
+    }
+    if (recvd < 0) {
+        if (!sock_.is_fatal()) return 0;  // Retry
+        throw FTL_Error(sock_.get_error_string());
+    }
+    return recvd;
 }
 
 ssize_t SocketConnection::send(const char* buffer, size_t len) {
-	return sock_.send(buffer, len, 0);
+    return sock_.send(buffer, len, 0);
 }
 
 ssize_t SocketConnection::writev(const struct iovec *iov, int iovcnt) {
-	ssize_t sent = sock_.writev(iov, iovcnt);
-	
-	ssize_t requested = 0;
-	for (int i = 0; i < iovcnt; i++) { requested += iov[i].iov_len; }
-
-	if (sent < 0) {
-		LOG(ERROR) << "writev(): " << sock_.get_error_string();
-		if (sock_.is_fatal()) {
-			return sent; 
-		}
-		sent = 0;
-	}
-	if (sent == requested) { return sent; }
-
-	std::vector<struct iovec> iov_local(iovcnt);
-	auto* iov_ptr = iov_local.data();
-	std::copy(iov, iov + iovcnt, iov_ptr);
-
-	ssize_t sent_total = sent;
-	int writev_calls = 1;
-	while (sent_total < requested) {
-		// ssize_t unsigned on Windows? Define as signed and use isntead of long
-		long iov_len = long(iov_ptr[0].iov_len) - long(sent);
-
-		if (iov_len < 0) {
-			// buffer was sent, update sent with remaining bytes and 
-			// repeat with next item in iov
-			sent = -iov_len;
-			iov_ptr++; iovcnt--;
-			continue;
-		}
-		
-		iov_ptr[0].iov_base = static_cast<char*>(iov_ptr[0].iov_base) + sent;
-		iov_ptr[0].iov_len = iov_ptr[0].iov_len - sent;
-
-		sent = sock_.writev(iov_ptr, iovcnt);
-		writev_calls++;
-
-		if (sent < 0) {
-			LOG(ERROR) << "writev(): " << sock_.get_error_string();
-			if (sock_.is_fatal()) {
-				return sent; 
-			}
-			sent = 0;
-		}
-
-		sent_total += sent;
-	}
-
-	LOG(2) << "message required " << writev_calls << " writev() calls";
-
-	if (can_increase_sock_buffer_) {
-		auto send_buf_size = sock_.get_send_buffer_size();
-		auto send_buf_size_new = size_t(sock_.get_send_buffer_size() * 1.5);
-
-		LOG(WARNING) << "Send buffer size "
-					 << (send_buf_size >> 10) << " KiB. "
-					 << "Increasing socket buffer size to "
-					 << (send_buf_size_new >> 10) << "KiB.";
-
-		if (!sock_.set_send_buffer_size(send_buf_size_new)) {
-			LOG(ERROR) << "could not increase send buffer size, "
-					<< "set_send_buffer_size() failed";
-			can_increase_sock_buffer_ = false;
-		}
-		else {
-			send_buf_size = sock_.get_send_buffer_size() ;
-			bool error = send_buf_size < send_buf_size_new;
-			LOG_IF(WARNING, error)
-				<< "could not increase send buffer size "
-				<< "(buffer size: " << send_buf_size << ")";
-			can_increase_sock_buffer_ &= !error;
-		}
-	}
-
-	return requested;
+    ssize_t sent = sock_.writev(iov, iovcnt);
+
+    ssize_t requested = 0;
+    for (int i = 0; i < iovcnt; i++) { requested += iov[i].iov_len; }
+
+    if (sent < 0) {
+        LOG(ERROR) << "writev(): " << sock_.get_error_string();
+        if (sock_.is_fatal()) {
+            return sent;
+        }
+        sent = 0;
+    }
+    if (sent == requested) { return sent; }
+
+    std::vector<struct iovec> iov_local(iovcnt);
+    auto* iov_ptr = iov_local.data();
+    std::copy(iov, iov + iovcnt, iov_ptr);
+
+    ssize_t sent_total = sent;
+    int writev_calls = 1;
+    while (sent_total < requested) {
+        // ssize_t unsigned on Windows? Define as signed and use isntead of long
+        int64_t iov_len = int64_t(iov_ptr[0].iov_len) - int64_t(sent);
+
+        if (iov_len < 0) {
+            // buffer was sent, update sent with remaining bytes and
+            // repeat with next item in iov
+            sent = -iov_len;
+            iov_ptr++;
+            iovcnt--;
+            continue;
+        }
+
+        iov_ptr[0].iov_base = static_cast<char*>(iov_ptr[0].iov_base) + sent;
+        iov_ptr[0].iov_len = iov_ptr[0].iov_len - sent;
+
+        sent = sock_.writev(iov_ptr, iovcnt);
+        writev_calls++;
+
+        if (sent < 0) {
+            LOG(ERROR) << "writev(): " << sock_.get_error_string();
+            if (sock_.is_fatal()) {
+                return sent;
+            }
+            sent = 0;
+        }
+
+        sent_total += sent;
+    }
+
+    LOG(2) << "message required " << writev_calls << " writev() calls";
+
+    if (can_increase_sock_buffer_) {
+        auto send_buf_size = sock_.get_send_buffer_size();
+        auto send_buf_size_new = size_t(sock_.get_send_buffer_size() * 1.5);
+
+        LOG(WARNING) << "Send buffer size "
+                     << (send_buf_size >> 10) << " KiB. "
+                     << "Increasing socket buffer size to "
+                     << (send_buf_size_new >> 10) << "KiB.";
+
+        if (!sock_.set_send_buffer_size(send_buf_size_new)) {
+            LOG(ERROR) << "could not increase send buffer size, "
+                    << "set_send_buffer_size() failed";
+            can_increase_sock_buffer_ = false;
+        } else {
+            send_buf_size = sock_.get_send_buffer_size();
+            bool error = send_buf_size < send_buf_size_new;
+            LOG_IF(WARNING, error)
+                << "could not increase send buffer size "
+                << "(buffer size: " << send_buf_size << ")";
+            can_increase_sock_buffer_ &= !error;
+        }
+    }
+
+    return requested;
 }
 
 bool SocketConnection::close() {
-	return sock_.close();
+    return sock_.close();
 }
 
 std::string SocketConnection::host() {
-	return get_host(addr_);
+    return get_host(addr_);
 }
 
 int SocketConnection::port() {
-	LOG(ERROR) << "port() not implemented";
-	return -1;
+    LOG(ERROR) << "port() not implemented";
+    return -1;
 }
 
 bool SocketConnection::set_recv_buffer_size(size_t sz) {
-	auto old = get_recv_buffer_size();
-	auto ok = sock_.set_recv_buffer_size(sz);
-	if (!ok) {
-		LOG(ERROR) << "setting socket send buffer size failed:"
-				   << sock_.get_error_string();
-	}
-	if (get_recv_buffer_size() == old) {
-		LOG(ERROR) << "recv buffer size was not changed";
-	}
-	return ok;
+    auto old = get_recv_buffer_size();
+    auto ok = sock_.set_recv_buffer_size(sz);
+    if (!ok) {
+        LOG(ERROR) << "setting socket send buffer size failed:"
+                   << sock_.get_error_string();
+    }
+    if (get_recv_buffer_size() == old) {
+        LOG(ERROR) << "recv buffer size was not changed";
+    }
+    return ok;
 }
 
 bool SocketConnection::set_send_buffer_size(size_t sz) {
-	auto old = get_send_buffer_size();
-	auto ok = sock_.set_send_buffer_size(sz);
-	if (!ok) {
-		LOG(ERROR) << "setting socket send buffer size failed:"
-				   << sock_.get_error_string();
-	}
-	if (get_send_buffer_size() == old) {
-		LOG(ERROR) << "send buffer size was not changed";
-	}
+    auto old = get_send_buffer_size();
+    auto ok = sock_.set_send_buffer_size(sz);
+    if (!ok) {
+        LOG(ERROR) << "setting socket send buffer size failed:"
+                   << sock_.get_error_string();
+    }
+    if (get_send_buffer_size() == old) {
+        LOG(ERROR) << "send buffer size was not changed";
+    }
 
-	return ok;
+    return ok;
 }
 
 size_t SocketConnection::get_recv_buffer_size() {
-	return sock_.get_recv_buffer_size();
+    return sock_.get_recv_buffer_size();
 }
 
 size_t SocketConnection::get_send_buffer_size() {
-	return sock_.get_send_buffer_size();
+    return sock_.get_send_buffer_size();
 }
 
 int SocketConnection::getSocketError() {
-	int val = 0;
-	socklen_t optlen = sizeof(val);
-	if (sock_.getsockopt(SOL_SOCKET, SO_ERROR, &val, &optlen) == 0) {
-		return val;
-	}
-	return errno;  // TODO: Windows.
+    int val = 0;
+    socklen_t optlen = sizeof(val);
+    if (sock_.getsockopt(SOL_SOCKET, SO_ERROR, &val, &optlen) == 0) {
+        return val;
+    }
+    return errno;  // TODO(Seb): Windows.
 }
 
 // SocketServer ////////////////////////////////////////////////////////////////
 
 socket_t SocketServer::fd() {
-	return sock_.fd();
+    return sock_.fd();
 }
 
 bool SocketServer::is_listening() {
-	return is_listening_;
+    return is_listening_;
 }
 
 bool SocketServer::bind(const SocketAddress &address, int backlog) {
-	bool retval = true;
+    bool retval = true;
 
-	retval &= sock_.bind(address) == 0;
-	if (!retval) {
-		auto msg = sock_.get_error_string();
-		throw FTL_Error("socket error:" + msg);
-	}
+    retval &= sock_.bind(address) == 0;
+    if (!retval) {
+        auto msg = sock_.get_error_string();
+        throw FTL_Error("socket error:" + msg);
+    }
 
-	retval &= sock_.listen(backlog) == 0;
-	if (!retval) {
-		auto msg = sock_.get_error_string();
-		throw FTL_Error("socket error:" + msg);
-	} else { is_listening_ = true; }
-	
-	addr_ = sock_.getsockname();
-	return retval;
+    retval &= sock_.listen(backlog) == 0;
+    if (!retval) {
+        auto msg = sock_.get_error_string();
+        throw FTL_Error("socket error:" + msg);
+    } else { is_listening_ = true; }
+
+    addr_ = sock_.getsockname();
+    return retval;
 }
 
 bool SocketServer::bind(int backlog) {
-	return bind(addr_, backlog);
+    return bind(addr_, backlog);
 }
 
 bool SocketServer::close() {
-	is_listening_ = false;
-	return sock_.close();
+    is_listening_ = false;
+    return sock_.close();
 }
 
 std::string SocketServer::host() {
-	return get_host(addr_);
+    return get_host(addr_);
 }
 
 int SocketServer::port() {
-	return get_port(addr_);
-}
\ No newline at end of file
+    return get_port(addr_);
+}
diff --git a/src/protocol/connection.hpp b/src/protocol/connection.hpp
index 5b320a63df7f21d68e8e915d9051ecc54bab4318..58d6b78e57606b05997885d8be6ee575c18da3be 100644
--- a/src/protocol/connection.hpp
+++ b/src/protocol/connection.hpp
@@ -1,11 +1,15 @@
-#ifndef _FTL_NET_SOCKET_CONNECTION_HPP_
-#define _FTL_NET_SOCKET_CONNECTION_HPP_
+/**
+ * @file connection.hpp
+ * @copyright Copyright (c) 2022 University of Turku, MIT License
+ * @author Sebastian Hahta
+ */
 
-#include <memory>
+#pragma once
 
+#include <memory>
+#include <string>
 #include <ftl/exception.hpp>
 #include <ftl/uri.hpp>
-
 #include "../socketImpl.hpp"
 
 namespace ftl {
@@ -18,65 +22,67 @@ namespace internal {
  *  Assumes IP socket.
  */
 class SocketConnection {
-protected:
-	Socket sock_;
-	SocketAddress addr_; // move to socket? save uri here
+ protected:
+    Socket sock_;
+    SocketAddress addr_;  // move to socket? save uri here
+
 
+    void connect(const SocketAddress &address, int timeout = 0);
 
-	void connect(const SocketAddress &address, int timeout=0);
+    SocketConnection() {}
 
-	SocketConnection() {};
+ private:
+    bool can_increase_sock_buffer_;
 
-private:
-	bool can_increase_sock_buffer_;
+ public:
+    SocketConnection(const SocketConnection&) = delete;
 
-public:
-	SocketConnection(const SocketConnection&) = delete;
+    SocketConnection(Socket socket, SocketAddress addr) :
+        sock_(socket), addr_(addr), can_increase_sock_buffer_(true) {}
 
-	SocketConnection(Socket socket, SocketAddress addr) :
-		sock_(socket), addr_(addr), can_increase_sock_buffer_(true) {};
-	
-	virtual ~SocketConnection();
+    virtual ~SocketConnection();
 
-	// connection accepts reads/writes
-	virtual bool is_valid();
+    // connection accepts reads/writes
+    virtual bool is_valid();
 
-	// OS socket file descriptor
-	virtual socket_t fd();
+    // OS socket file descriptor
+    virtual socket_t fd();
 
-	virtual ftl::URI uri();
-	virtual ftl::URI::scheme_t scheme() const;
+    virtual ftl::URI uri();
+    virtual ftl::URI::scheme_t scheme() const;
 
-	virtual void connect(const ftl::URI& uri, int timeout=0) = 0;
-	
-	// virtual void connect(int timeout=0); // TODO: set uri in constructor
-	
-	// close connection, return true if operation successful. never throws.
-	virtual bool close();
+    virtual void connect(const ftl::URI& uri, int timeout = 0) = 0;
 
-	// process next item in buffer, returns true if available and sets offset
-	// to number of bytes to skip in buffer (variable length headers etc.)
-	virtual bool prepare_next(char* buffer, size_t len, size_t &offset)
-		{ offset = 0; return true; }
+    // virtual void connect(int timeout=0); // TODO: set uri in constructor
 
-	// send, returns number of bytes sent
-	virtual ssize_t send(const char* buffer, size_t len);
-	// receive, returns number of bytes received
-	virtual ssize_t recv(char *buffer, size_t len);
-	// scatter write, return number of bytes sent. always sends all data in iov.
-	virtual ssize_t writev(const struct iovec *iov, int iovcnt);
+    // close connection, return true if operation successful. never throws.
+    virtual bool close();
 
-	virtual bool set_recv_buffer_size(size_t sz);
-	virtual bool set_send_buffer_size(size_t sz);
-	virtual size_t get_recv_buffer_size();
-	virtual size_t get_send_buffer_size();
+    // process next item in buffer, returns true if available and sets offset
+    // to number of bytes to skip in buffer (variable length headers etc.)
+    virtual bool prepare_next(char* buffer, size_t len, size_t &offset) {
+        offset = 0;
+        return true;
+    }
 
-	int getSocketError();
+    // send, returns number of bytes sent
+    virtual ssize_t send(const char* buffer, size_t len);
+    // receive, returns number of bytes received
+    virtual ssize_t recv(char *buffer, size_t len);
+    // scatter write, return number of bytes sent. always sends all data in iov.
+    virtual ssize_t writev(const struct iovec *iov, int iovcnt);
 
-	int is_fatal(int code=0);
+    virtual bool set_recv_buffer_size(size_t sz);
+    virtual bool set_send_buffer_size(size_t sz);
+    virtual size_t get_recv_buffer_size();
+    virtual size_t get_send_buffer_size();
 
-	virtual std::string host();
-	virtual int port();
+    int getSocketError();
+
+    int is_fatal(int code = 0);
+
+    virtual std::string host();
+    virtual int port();
 };
 
 /** Socket server, wraps listening sockets. Transport protocols can
@@ -87,45 +93,43 @@ public:
  *  Assumes IP socket.
  */
 class SocketServer {
-protected:
-	Socket sock_;
-	SocketAddress addr_;
-	bool is_listening_;
+ protected:
+    Socket sock_;
+    SocketAddress addr_;
+    bool is_listening_;
 
-	SocketServer() {}
+    SocketServer() {}
 
-public:
-	SocketServer(Socket sock, SocketAddress addr) :
-		sock_(sock), addr_(addr), is_listening_(false) {};
-	
-	// return OS file descriptor (for select()/poll()/etc.)
-	socket_t fd();
+ public:
+    SocketServer(Socket sock, SocketAddress addr) :
+        sock_(sock), addr_(addr), is_listening_(false) {}
 
-	virtual bool is_listening();
+    // return OS file descriptor (for select()/poll()/etc.)
+    socket_t fd();
 
-	// bind and listen socket, throws exception on error
-	virtual bool bind(const SocketAddress &address, int backlog=0);
-	virtual bool bind(int backlog=0);
+    virtual bool is_listening();
 
-	// accept connection, throws exception on error
-	virtual std::unique_ptr<SocketConnection> accept() = 0;
+    // bind and listen socket, throws exception on error
+    virtual bool bind(const SocketAddress &address, int backlog = 0);
+    virtual bool bind(int backlog = 0);
 
-	/// stop accepting new connection and close underlying socket
-	virtual bool close();
+    // accept connection, throws exception on error
+    virtual std::unique_ptr<SocketConnection> accept() = 0;
 
-	virtual ftl::URI uri() = 0;
+    /// stop accepting new connection and close underlying socket
+    virtual bool close();
 
-	/// avoid use, use URI etc. instead
-	virtual std::string host();
-	/// avoid use, use URI etc. instead
-	virtual int port();
+    virtual ftl::URI uri() = 0;
+
+    /// avoid use, use URI etc. instead
+    virtual std::string host();
+    /// avoid use, use URI etc. instead
+    virtual int port();
 };
 
 // SocketConnection factory
 std::unique_ptr<SocketConnection> createConnection(const ftl::URI &uri);
 
-} // namespace internal
-} // namespace net
-} // namespace ftl
-
-#endif
\ No newline at end of file
+}  // namespace internal
+}  // namespace net
+}  // namespace ftl
diff --git a/src/protocol/factory.cpp b/src/protocol/factory.cpp
index e966edb619401b46a42109d03510440705e74395..573a299f8e8590e67874afad5fb36b3278455b6b 100644
--- a/src/protocol/factory.cpp
+++ b/src/protocol/factory.cpp
@@ -1,8 +1,12 @@
-#include <loguru.hpp>
+/**
+ * @file factory.cpp
+ * @copyright Copyright (c) 2022 University of Turku, MIT License
+ * @author Sebastian Hahta
+ */
 
-#include <ftl/exception.hpp>
 #include <ftl/protocol/config.h>
-
+#include <loguru.hpp>
+#include <ftl/exception.hpp>
 #include "connection.hpp"
 #include "tcp.hpp"
 #include "tls.hpp"
@@ -19,26 +23,26 @@ using ftl::net::internal::Connection_WSS;
 using ftl::URI;
 
 std::unique_ptr<SocketConnection> ftl::net::internal::createConnection(const URI &uri) {
-	if (uri.getProtocol() == URI::SCHEME_TCP) {
-		auto c = std::make_unique<Connection_TCP>();
-		return c;
+    if (uri.getProtocol() == URI::SCHEME_TCP) {
+        auto c = std::make_unique<Connection_TCP>();
+        return c;
 
-	} else if (uri.getProtocol() == URI::SCHEME_WS) {
-		auto c = std::make_unique<Connection_WS>();
-		return c;
+    } else if (uri.getProtocol() == URI::SCHEME_WS) {
+        auto c = std::make_unique<Connection_WS>();
+        return c;
 
-	} else if (uri.getProtocol() == URI::SCHEME_WSS) {
+    } else if (uri.getProtocol() == URI::SCHEME_WSS) {
 #ifdef HAVE_GNUTLS
-		auto c = std::make_unique<Connection_WSS>();
-		return c;
+        auto c = std::make_unique<Connection_WSS>();
+        return c;
 #else
-		throw FTL_Error("built without TLS support");
+        throw FTL_Error("built without TLS support");
 #endif
 
-	} else {
-		//LOG(ERROR) << "can't connect to: " << uri.to_string();
-		throw FTL_Error("unrecognised connection protocol: " << uri.to_string());
-	}
+    } else {
+        // LOG(ERROR) << "can't connect to: " << uri.to_string();
+        throw FTL_Error("unrecognised connection protocol: " << uri.to_string());
+    }
 
-	return nullptr;
-}
\ No newline at end of file
+    return nullptr;
+}
diff --git a/src/protocol/tcp.cpp b/src/protocol/tcp.cpp
index e912bf729201f3474753008c81ae0659bdbd7fe3..06460f7c26c185d1ab2de4ab07faec94076e75a5 100644
--- a/src/protocol/tcp.cpp
+++ b/src/protocol/tcp.cpp
@@ -1,67 +1,76 @@
+/**
+ * @file tcp.cpp
+ * @copyright Copyright (c) 2022 University of Turku, MIT License
+ * @author Sebastian Hahta
+ */
 
-
+#include <string>
+#include <memory>
 #include <ftl/exception.hpp>
 #include "tcp.hpp"
 #include <ftl/lib/loguru.hpp>
 
-using namespace ftl::net::internal;
+using ftl::net::internal::Connection_TCP;
+using ftl::net::internal::SocketConnection;
+using ftl::net::internal::Server_TCP;
+using ftl::net::internal::SocketAddress;
+using ftl::net::internal::Socket;
 
 // Connection_TCP //////////////////////////////////////////////////////////////
 
 Connection_TCP::Connection_TCP(Socket sock, SocketAddress addr) : SocketConnection(sock, addr) {
-	if (!sock_.set_nodelay(true) || !sock_.get_nodelay()) {
-		LOG(ERROR) << "Could not set TCP_NODELAY";
-	}
+    if (!sock_.set_nodelay(true) || !sock_.get_nodelay()) {
+        LOG(ERROR) << "Could not set TCP_NODELAY";
+    }
 }
 
 Connection_TCP::Connection_TCP() : SocketConnection(create_tcp_socket(), {}) {
-	if (!sock_.set_nodelay(true) || !sock_.get_nodelay()) {
-		LOG(ERROR) << "Could not set TCP_NODELAY";
-	}
+    if (!sock_.set_nodelay(true) || !sock_.get_nodelay()) {
+        LOG(ERROR) << "Could not set TCP_NODELAY";
+    }
 }
 
 
 bool Connection_TCP::connect(const std::string &hostname, int port, int timeout) {
-	if (!resolve_inet_address(hostname, port, addr_)) {
-		throw FTL_Error("could not resolve hostname: " + hostname);
-	}
-	auto err = sock_.connect(addr_);
-	if (err < 0) {
-		throw FTL_Error("connect() error: " + sock_.get_error_string());
-	}
+    if (!resolve_inet_address(hostname, port, addr_)) {
+        throw FTL_Error("could not resolve hostname: " + hostname);
+    }
+    auto err = sock_.connect(addr_);
+    if (err < 0) {
+        throw FTL_Error("connect() error: " + sock_.get_error_string());
+    }
 
-	return true;
+    return true;
 }
 
 void Connection_TCP::connect(const ftl::URI& uri, int timeout) {
-	if (!connect(uri.getHost(), uri.getPort(), timeout)) {
-		throw FTL_Error("Could not open TCP connection");
-	}
+    if (!connect(uri.getHost(), uri.getPort(), timeout)) {
+        throw FTL_Error("Could not open TCP connection");
+    }
 }
 
 // Server_TCP //////////////////////////////////////////////////////////////////
 
 Server_TCP::Server_TCP(const std::string &hostname, int port) :
-		SocketServer(create_tcp_socket(), {}), host_(hostname) {
-	
-	if (!resolve_inet_address(hostname, port, addr_)) {
-		throw FTL_Error("could not resolve " + hostname);
-	}
+        SocketServer(create_tcp_socket(), {}), host_(hostname) {
+    if (!resolve_inet_address(hostname, port, addr_)) {
+        throw FTL_Error("could not resolve " + hostname);
+    }
 
-	int enable = 1;
-	if (sock_.setsockopt(SOL_SOCKET, SO_REUSEADDR, (char*)(&enable), sizeof(int)) < 0) {
-		LOG(ERROR) << "Setting SO_REUSEADDR failed";
-	}
+    int enable = 1;
+    if (sock_.setsockopt(SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&enable), sizeof(int)) < 0) {
+        LOG(ERROR) << "Setting SO_REUSEADDR failed";
+    }
 }
 
 std::unique_ptr<SocketConnection> Server_TCP::accept() {
-	SocketAddress addr;
-	auto sock = sock_.accept(addr);
-	auto connection = std::unique_ptr<Connection_TCP>(
-		new Connection_TCP(sock, addr)); // throws on error
-	return connection;
+    SocketAddress addr;
+    auto sock = sock_.accept(addr);
+    auto connection = std::unique_ptr<Connection_TCP>(
+        new Connection_TCP(sock, addr));  // throws on error
+    return connection;
 }
 
 ftl::URI Server_TCP::uri() {
-	return ftl::URI("tcp://" + host() + ":" + std::to_string(port()));
-}
\ No newline at end of file
+    return ftl::URI("tcp://" + host() + ":" + std::to_string(port()));
+}
diff --git a/src/protocol/tcp.hpp b/src/protocol/tcp.hpp
index 5e0fc56b4672dcb84a1b02d1bf536f5345fcdd79..ce9b9278c57cdffd4a647c9589de2fec58be8c32 100644
--- a/src/protocol/tcp.hpp
+++ b/src/protocol/tcp.hpp
@@ -1,6 +1,13 @@
-#ifndef _FTL_NET_SOCKET_CONNECTION_TCP_HPP_
-#define _FTL_NET_SOCKET_CONNECTION_TCP_HPP_
+/**
+ * @file tcp.hpp
+ * @copyright Copyright (c) 2022 University of Turku, MIT License
+ * @author Sebastian Hahta
+ */
 
+#pragma once
+
+#include <string>
+#include <memory>
 #include <ftl/exception.hpp>
 #include <ftl/uri.hpp>
 
@@ -14,36 +21,34 @@ namespace internal {
 // TCP client/server (directly uses socket without additional processing)
 
 class Server_TCP : public SocketServer {
-private:
-	std::string host_;
+ private:
+    std::string host_;
 
-protected:
-	using SocketServer::SocketServer;
+ protected:
+    using SocketServer::SocketServer;
 
-public:
-	Server_TCP(const std::string& hostname, int port);
-	std::unique_ptr<SocketConnection> accept() override;
+ public:
+    Server_TCP(const std::string& hostname, int port);
+    std::unique_ptr<SocketConnection> accept() override;
 
-	ftl::URI uri() override;
+    ftl::URI uri() override;
 };
 
 class Connection_TCP : public SocketConnection {
-private:
-	friend class Server_TCP;
-
-protected:
-	Connection_TCP(Socket sock, SocketAddress addr);
-
-public:
-	Connection_TCP();
-	
-	ftl::URI::scheme_t scheme() const override { return ftl::URI::SCHEME_TCP; }
-	bool connect(const std::string &hostname, int port, int timeout=0);
-	void connect(const ftl::URI& uri, int timeout=0) override;
-};
+ private:
+    friend class Server_TCP;
+
+ protected:
+    Connection_TCP(Socket sock, SocketAddress addr);
 
-} // namespace internal
-} // namespace net
-} // namespace ftl
+ public:
+    Connection_TCP();
+
+    ftl::URI::scheme_t scheme() const override { return ftl::URI::SCHEME_TCP; }
+    bool connect(const std::string &hostname, int port, int timeout = 0);
+    void connect(const ftl::URI& uri, int timeout = 0) override;
+};
 
-#endif
\ No newline at end of file
+}  // namespace internal
+}  // namespace net
+}  // namespace ftl
diff --git a/src/protocol/tls.cpp b/src/protocol/tls.cpp
index 42175003da135674c92aeb763c1677d812f7bde7..cbc17386ec2d67b68b752c0cfaeae2b53c82a1e3 100644
--- a/src/protocol/tls.cpp
+++ b/src/protocol/tls.cpp
@@ -1,9 +1,16 @@
+/**
+ * @file tls.cpp
+ * @copyright Copyright (c) 2022 University of Turku, MIT License
+ * @author Sebastian Hahta
+ */
+
 #include "tls.hpp"
 
 #ifdef HAVE_GNUTLS
 
 #include <sstream>
 #include <iomanip>
+#include <string>
 
 #include <ftl/exception.hpp>
 #include <ftl/lib/loguru.hpp>
@@ -14,126 +21,125 @@ using uchar = unsigned char;
 /** get basic certificate info: Distinguished Name (DN), issuer DN,
  *  certificate fingerprint */
 std::string get_cert_info(gnutls_session_t session) {
-	const gnutls_datum_t *cert_list;
-	unsigned int cert_list_size = 0;
+    const gnutls_datum_t *cert_list;
+    unsigned int cert_list_size = 0;
+
+    cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
 
-	cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
+    std::string str = "";
 
-	std::string str = "";
+    if (cert_list_size > 0) {
+        gnutls_x509_crt_t cert;
+        char data[256];
+        size_t size;
 
-	if (cert_list_size > 0) {
-		gnutls_x509_crt_t cert;
-		char data[256];
-		size_t size;
+        gnutls_x509_crt_init(&cert);
 
-		gnutls_x509_crt_init(&cert);
+        gnutls_x509_crt_import(cert, &cert_list[0],
+                                GNUTLS_X509_FMT_DER);
 
-		gnutls_x509_crt_import(cert, &cert_list[0],
-								GNUTLS_X509_FMT_DER);
+        size = sizeof(data);
+        gnutls_x509_crt_get_dn(cert, data, &size);
+        str += "DN: " + std::string(data);
 
-		size = sizeof(data);
-		gnutls_x509_crt_get_dn(cert, data, &size);
-		str += "DN: " + std::string(data);
+        size = sizeof(data);
+        gnutls_x509_crt_get_issuer_dn(cert, data, &size);
+        str += "; Issuer DN: " + std::string(data);
 
-		size = sizeof(data);
-		gnutls_x509_crt_get_issuer_dn(cert, data, &size);
-		str += "; Issuer DN: " + std::string(data);
+        size = sizeof(data);
+        gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA1, data, &size);
+        std::stringstream ss;
+        ss << std::hex << std::setfill('0');
+        for (size_t i = 0; i < size; i++) {
+            ss << std::setw(2) << int((reinterpret_cast<uchar*>(data))[i]);
+            if (i != (size - 1)) ss << ":";
+        }
+        str += "; certificate fingerprint (SHA1): " + ss.str();
 
-		size = sizeof(data);
-		gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA1, data, &size);
-		std::stringstream ss;
-		ss << std::hex << std::setfill('0');
-		for (size_t i = 0; i < size; i++) {
-			ss << std::setw(2) << int(((uchar*) data)[i]);
-			if (i != (size - 1)) ss << ":";
-		}
-		str += "; certificate fingerprint (SHA1): " + ss.str();
+        gnutls_x509_crt_deinit(cert);
+    }
 
-		gnutls_x509_crt_deinit(cert);
-	}
-	
-	return str;
+    return str;
 }
 
 int Connection_TLS::check_gnutls_error_(int errcode) {
-	if (errcode < 0 && gnutls_error_is_fatal(errcode) == 0) {
-		Connection_TCP::close();
-	}
-	
-	if (errcode < 0) {
-		auto msg = gnutls_strerror(errcode);
-		throw FTL_Error(msg);
-	}
-
-	return errcode;
-};
+    if (errcode < 0 && gnutls_error_is_fatal(errcode) == 0) {
+        Connection_TCP::close();
+    }
+
+    if (errcode < 0) {
+        auto msg = gnutls_strerror(errcode);
+        throw FTL_Error(msg);
+    }
+
+    return errcode;
+}
 
 bool Connection_TLS::connect(const std::string& hostname, int port, int timeout) {
-	// TODO: throw if already connected 
+    // TODO(Seb): throw if already connected
 
-	check_gnutls_error_(gnutls_certificate_allocate_credentials(&xcred_));
-	check_gnutls_error_(gnutls_certificate_set_x509_system_trust(xcred_));
-	check_gnutls_error_(gnutls_init(&session_, GNUTLS_CLIENT));
-	check_gnutls_error_(gnutls_server_name_set(session_, GNUTLS_NAME_DNS, hostname.c_str(), hostname.length()));
+    check_gnutls_error_(gnutls_certificate_allocate_credentials(&xcred_));
+    check_gnutls_error_(gnutls_certificate_set_x509_system_trust(xcred_));
+    check_gnutls_error_(gnutls_init(&session_, GNUTLS_CLIENT));
+    check_gnutls_error_(gnutls_server_name_set(session_, GNUTLS_NAME_DNS, hostname.c_str(), hostname.length()));
 
-	gnutls_session_set_verify_cert(session_, hostname.c_str(), 0);
-	check_gnutls_error_(gnutls_set_default_priority(session_));
+    gnutls_session_set_verify_cert(session_, hostname.c_str(), 0);
+    check_gnutls_error_(gnutls_set_default_priority(session_));
 
-	if (!Connection_TCP::connect(hostname, port, timeout)) {
-		throw FTL_Error("TLS connection failed");
-	}
+    if (!Connection_TCP::connect(hostname, port, timeout)) {
+        throw FTL_Error("TLS connection failed");
+    }
 
-	check_gnutls_error_(gnutls_credentials_set(session_, GNUTLS_CRD_CERTIFICATE, xcred_));
+    check_gnutls_error_(gnutls_credentials_set(session_, GNUTLS_CRD_CERTIFICATE, xcred_));
 
-	gnutls_transport_set_int(session_, sock_.fd());
-	gnutls_handshake_set_timeout(session_, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
+    gnutls_transport_set_int(session_, sock_.fd());
+    gnutls_handshake_set_timeout(session_, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
 
-	check_gnutls_error_(gnutls_handshake(session_));
+    check_gnutls_error_(gnutls_handshake(session_));
 
-	LOG(INFO) << "TLS connection established: "
-			  << gnutls_session_get_desc(session_) << "; "
-			  << get_cert_info(session_);
+    LOG(INFO) << "TLS connection established: "
+              << gnutls_session_get_desc(session_) << "; "
+              << get_cert_info(session_);
 
-	// try a few times? (included in gnutls example)
-	// do { ... } while (retval < 0 && gnutls_error_is_fatal(retval) == 0);
+    // try a few times? (included in gnutls example)
+    // do { ... } while (retval < 0 && gnutls_error_is_fatal(retval) == 0);
 
-	return true;
+    return true;
 }
 
 bool Connection_TLS::close() {
-	if (sock_.is_open()) {
-		gnutls_bye(session_, GNUTLS_SHUT_RDWR);
-	}
-	return Connection_TCP::close();
+    if (sock_.is_open()) {
+        gnutls_bye(session_, GNUTLS_SHUT_RDWR);
+    }
+    return Connection_TCP::close();
 }
 
 ssize_t Connection_TLS::recv(char *buffer, size_t len) {
-	auto recvd = gnutls_record_recv(session_, buffer, len);
-	if (recvd == 0) {
-		LOG(1) << "recv returned 0 (buffer size " << len << "), closing connection";
-		close();
-	}
+    auto recvd = gnutls_record_recv(session_, buffer, len);
+    if (recvd == 0) {
+        LOG(1) << "recv returned 0 (buffer size " << len << "), closing connection";
+        close();
+    }
 
-	return check_gnutls_error_(recvd);
+    return check_gnutls_error_(recvd);
 }
 
 ssize_t Connection_TLS::send(const char* buffer, size_t len) {
-	return check_gnutls_error_(gnutls_record_send(session_, buffer, len));
+    return check_gnutls_error_(gnutls_record_send(session_, buffer, len));
 }
 
 ssize_t Connection_TLS::writev(const struct iovec *iov, int iovcnt) {
-	gnutls_record_cork(session_);
-
-	for (int i = 0; i < iovcnt; i++) {
-		size_t sent = 0;
-		do {
-			// should always succeed and cache whole buffer (no error checking)
-			sent += send((const char*) iov[i].iov_base, iov[i].iov_len);
-		}
-		while(sent < iov[i].iov_len);
-	}
-	
-	return check_gnutls_error_(gnutls_record_uncork(session_, GNUTLS_RECORD_WAIT));
+    gnutls_record_cork(session_);
+
+    for (int i = 0; i < iovcnt; i++) {
+        size_t sent = 0;
+        do {
+            // should always succeed and cache whole buffer (no error checking)
+            sent += send((const char*) iov[i].iov_base, iov[i].iov_len);
+        } while (sent < iov[i].iov_len);
+    }
+
+    return check_gnutls_error_(gnutls_record_uncork(session_, GNUTLS_RECORD_WAIT));
 }
 
-#endif
\ No newline at end of file
+#endif
diff --git a/src/protocol/tls.hpp b/src/protocol/tls.hpp
index 65cad60cdfcd47746616a1c96186b66a515b072b..ca206301b3a4c16379d262e09b96ab09c9a9bbeb 100644
--- a/src/protocol/tls.hpp
+++ b/src/protocol/tls.hpp
@@ -1,6 +1,13 @@
+/**
+ * @file tls.hpp
+ * @copyright Copyright (c) 2022 University of Turku, MIT License
+ * @author Sebastian Hahta
+ */
+
 #pragma once
 
 #include <ftl/protocol/config.h>
+#include <string>
 
 #ifdef HAVE_GNUTLS
 
@@ -19,29 +26,29 @@ namespace net {
 namespace internal {
 
 class Connection_TLS : public Connection_TCP {
-public:
-	Connection_TLS() {};
-	Connection_TLS(const std::string &hostname, int port, int timeout=0);
-
-	bool connect(const std::string &hostname, int port, int timeout=0);
-
-	bool close() override;
-	
-protected:
-	ssize_t recv(char *buffer, size_t len) override;
-	ssize_t send(const char* buffer, size_t len) override;
-	ssize_t writev(const struct iovec *iov, int iovcnt) override;
-	
-	int check_gnutls_error_(int errcode); // check for fatal error and throw
-
-private:
-	gnutls_session_t session_;
-	gnutls_certificate_credentials_t xcred_;
+ public:
+    Connection_TLS() {}
+    Connection_TLS(const std::string &hostname, int port, int timeout = 0);
+
+    bool connect(const std::string &hostname, int port, int timeout = 0);
+
+    bool close() override;
+
+ protected:
+    ssize_t recv(char *buffer, size_t len) override;
+    ssize_t send(const char* buffer, size_t len) override;
+    ssize_t writev(const struct iovec *iov, int iovcnt) override;
+
+    int check_gnutls_error_(int errcode);  // check for fatal error and throw
+
+ private:
+    gnutls_session_t session_;
+    gnutls_certificate_credentials_t xcred_;
 };
 
 
-}
-}
-}
+}  // namespace internal
+}  // namespace net
+}  // namespace ftl
 
-#endif // HAVE_GNUTLS
+#endif  // HAVE_GNUTLS
diff --git a/src/protocol/websocket.cpp b/src/protocol/websocket.cpp
index 282c471a81eaebdfc9304c1d86b8a286e69886a9..b1c64ea45cbdec1aaaf4bb4b98b65f49a60935fe 100644
--- a/src/protocol/websocket.cpp
+++ b/src/protocol/websocket.cpp
@@ -1,3 +1,11 @@
+/**
+ * @file websocket.cpp
+ * @copyright Copyright (c) 2022 University of Turku, MIT License
+ * @author Sebastian Hahta
+ */
+
+#include <string>
+#include <algorithm>
 #include "websocket.hpp"
 #include <ftl/lib/loguru.hpp>
 
@@ -9,9 +17,9 @@ using uchar = unsigned char;
 #include <gnutls/crypto.h>
 
 inline uint32_t secure_rnd() {
-	uint32_t rnd;
-	gnutls_rnd(GNUTLS_RND_NONCE, &rnd, sizeof(uint32_t));
-	return rnd;
+    uint32_t rnd;
+    gnutls_rnd(GNUTLS_RND_NONCE, &rnd, sizeof(uint32_t));
+    return rnd;
 }
 #else
 #include <random>
@@ -19,323 +27,321 @@ static std::random_device rd_;
 static std::uniform_int_distribution<uint32_t> dist_(0);
 
 inline uint32_t secure_rnd() {
-	// TODO
-	return dist_(rd_);
+    // TODO(Seb)
+    return dist_(rd_);
 }
 #endif
 
 using ftl::URI;
-using namespace ftl::net::internal;
+using ftl::net::internal::WebSocketBase;
+using ftl::net::internal::Connection_TCP;
+using ftl::net::internal::Connection_TLS;
 
 /* Taken from easywsclient */
 struct wsheader_type {
-	unsigned header_size;
-	bool fin;
-	bool mask;
-	enum opcode_type {
-		CONTINUATION = 0x0,
-		TEXT_FRAME = 0x1,
-		BINARY_FRAME = 0x2,
-		CLOSE = 8,
-		PING = 9,
-		PONG = 0xa,
-	} opcode;
-	int N0;
-	uint64_t N;
-	uint8_t masking_key[4];
+    unsigned header_size;
+    bool fin;
+    bool mask;
+    enum opcode_type {
+        CONTINUATION = 0x0,
+        TEXT_FRAME = 0x1,
+        BINARY_FRAME = 0x2,
+        CLOSE = 8,
+        PING = 9,
+        PONG = 0xa,
+    } opcode;
+    int N0;
+    uint64_t N;
+    uint8_t masking_key[4];
 };
 
 struct ws_options {
-	std::string userinfo = "";
+    std::string userinfo = "";
 };
 
 // prepare ws header
 int ws_prepare(wsheader_type::opcode_type op, bool useMask, uint32_t mask,
-				size_t len, char *data, size_t maxlen) {
-
-	uint8_t* masking_key = reinterpret_cast<uint8_t*>(&mask);
-
-	char *header = data;
-	size_t header_size = 2 + (len >= 126 ? 2 : 0) + (len >= 65536 ? 6 : 0) + (useMask ? 4 : 0);
-	if (header_size > maxlen) return -1;
-
-	memset(header, 0, header_size);
-	header[0] = 0x80 | op;
-	
-	if (len < 126) {
-		header[1] = (len & 0xff) | (useMask ? 0x80 : 0);
-		if (useMask) {
-			header[2] = masking_key[0];
-			header[3] = masking_key[1];
-			header[4] = masking_key[2];
-			header[5] = masking_key[3];
-		}
-	} else if (len < 65536) {
-		header[1] = 126 | (useMask ? 0x80 : 0);
-		header[2] = (len >> 8) & 0xff;
-		header[3] = (len >> 0) & 0xff;
-		if (useMask) {
-			header[4] = masking_key[0];
-			header[5] = masking_key[1];
-			header[6] = masking_key[2];
-			header[7] = masking_key[3];
-		}
-	} else {
-		header[1] = 127 | (useMask ? 0x80 : 0);
-		header[2] = (len >> 56) & 0xff;
-		header[3] = (len >> 48) & 0xff;
-		header[4] = (len >> 40) & 0xff;
-		header[5] = (len >> 32) & 0xff;
-		header[6] = (len >> 24) & 0xff;
-		header[7] = (len >> 16) & 0xff;
-		header[8] = (len >>  8) & 0xff;
-		header[9] = (len >>  0) & 0xff;
-		if (useMask) {
-			header[10] = masking_key[0];
-			header[11] = masking_key[1];
-			header[12] = masking_key[2];
-			header[13] = masking_key[3];
-		}
-	}
-
-	return int(header_size);
+                size_t len, char *data, size_t maxlen) {
+    uint8_t* masking_key = reinterpret_cast<uint8_t*>(&mask);
+
+    char *header = data;
+    size_t header_size = 2 + (len >= 126 ? 2 : 0) + (len >= 65536 ? 6 : 0) + (useMask ? 4 : 0);
+    if (header_size > maxlen) return -1;
+
+    memset(header, 0, header_size);
+    header[0] = 0x80 | op;
+
+    if (len < 126) {
+        header[1] = (len & 0xff) | (useMask ? 0x80 : 0);
+        if (useMask) {
+            header[2] = masking_key[0];
+            header[3] = masking_key[1];
+            header[4] = masking_key[2];
+            header[5] = masking_key[3];
+        }
+    } else if (len < 65536) {
+        header[1] = 126 | (useMask ? 0x80 : 0);
+        header[2] = (len >> 8) & 0xff;
+        header[3] = (len >> 0) & 0xff;
+        if (useMask) {
+            header[4] = masking_key[0];
+            header[5] = masking_key[1];
+            header[6] = masking_key[2];
+            header[7] = masking_key[3];
+        }
+    } else {
+        header[1] = 127 | (useMask ? 0x80 : 0);
+        header[2] = (len >> 56) & 0xff;
+        header[3] = (len >> 48) & 0xff;
+        header[4] = (len >> 40) & 0xff;
+        header[5] = (len >> 32) & 0xff;
+        header[6] = (len >> 24) & 0xff;
+        header[7] = (len >> 16) & 0xff;
+        header[8] = (len >>  8) & 0xff;
+        header[9] = (len >>  0) & 0xff;
+        if (useMask) {
+            header[10] = masking_key[0];
+            header[11] = masking_key[1];
+            header[12] = masking_key[2];
+            header[13] = masking_key[3];
+        }
+    }
+
+    return static_cast<int>(header_size);
 }
 
 // parse ws header, returns true on success
-// TODO: return error code for different results (not enough bytes in buffer
-//		 to build the header vs corrputed/invalid header)
-bool ws_parse(uchar *data, size_t len, wsheader_type& ws) {
-	if (len < 2) return false;
-	
-	ws.fin = (data[0] & 0x80) == 0x80;
-	ws.opcode = (wsheader_type::opcode_type) (data[0] & 0x0f);
-	ws.mask = (data[1] & 0x80) == 0x80;
-	ws.N0 = (data[1] & 0x7f);
-	ws.header_size = 2 + (ws.N0 == 126? 2 : 0) + (ws.N0 == 127? 8 : 0) + (ws.mask? 4 : 0);
-
-	if (len < ws.header_size) return false;
-
-	// invalid opcode, corrupted header?
-	if ((ws.opcode > 10) || ((ws.opcode > 2) && (ws.opcode < 8))) return false;
-
-	int i = 0;
-	if (ws.N0 < 126) {
-		ws.N = ws.N0;
-		i = 2;
-	} else if (ws.N0 == 126) {
-		ws.N = 0;
-		ws.N |= ((uint64_t) data[2]) << 8;
-		ws.N |= ((uint64_t) data[3]) << 0;
-		i = 4;
-	} else if (ws.N0 == 127) {
-		ws.N = 0;
-		ws.N |= ((uint64_t) data[2]) << 56;
-		ws.N |= ((uint64_t) data[3]) << 48;
-		ws.N |= ((uint64_t) data[4]) << 40;
-		ws.N |= ((uint64_t) data[5]) << 32;
-		ws.N |= ((uint64_t) data[6]) << 24;
-		ws.N |= ((uint64_t) data[7]) << 16;
-		ws.N |= ((uint64_t) data[8]) << 8;
-		ws.N |= ((uint64_t) data[9]) << 0;
-		i = 10;
-	}
-	
-	if (ws.mask) {
-		ws.masking_key[0] = ((uint8_t) data[i+0]) << 0;
-		ws.masking_key[1] = ((uint8_t) data[i+1]) << 0;
-		ws.masking_key[2] = ((uint8_t) data[i+2]) << 0;
-		ws.masking_key[3] = ((uint8_t) data[i+3]) << 0;
-	} else {
-		ws.masking_key[0] = 0;
-		ws.masking_key[1] = 0;
-		ws.masking_key[2] = 0;
-		ws.masking_key[3] = 0;
-	}
-	
-	return true;
+// TODO(Seb): return error code for different results (not enough bytes in buffer
+//    to build the header vs corrputed/invalid header)
+bool ws_parse(uchar *data, size_t len, wsheader_type *ws) {
+    if (len < 2) return false;
+
+    ws->fin = (data[0] & 0x80) == 0x80;
+    ws->opcode = (wsheader_type::opcode_type) (data[0] & 0x0f);
+    ws->mask = (data[1] & 0x80) == 0x80;
+    ws->N0 = (data[1] & 0x7f);
+    ws->header_size = 2 + (ws->N0 == 126? 2 : 0) + (ws->N0 == 127? 8 : 0) + (ws->mask? 4 : 0);
+
+    if (len < ws->header_size) return false;
+
+    // invalid opcode, corrupted header?
+    if ((ws->opcode > 10) || ((ws->opcode > 2) && (ws->opcode < 8))) return false;
+
+    int i = 0;
+    if (ws->N0 < 126) {
+        ws->N = ws->N0;
+        i = 2;
+    } else if (ws->N0 == 126) {
+        ws->N = 0;
+        ws->N |= ((uint64_t) data[2]) << 8;
+        ws->N |= ((uint64_t) data[3]) << 0;
+        i = 4;
+    } else if (ws->N0 == 127) {
+        ws->N = 0;
+        ws->N |= ((uint64_t) data[2]) << 56;
+        ws->N |= ((uint64_t) data[3]) << 48;
+        ws->N |= ((uint64_t) data[4]) << 40;
+        ws->N |= ((uint64_t) data[5]) << 32;
+        ws->N |= ((uint64_t) data[6]) << 24;
+        ws->N |= ((uint64_t) data[7]) << 16;
+        ws->N |= ((uint64_t) data[8]) << 8;
+        ws->N |= ((uint64_t) data[9]) << 0;
+        i = 10;
+    }
+
+    if (ws->mask) {
+        ws->masking_key[0] = ((uint8_t) data[i+0]) << 0;
+        ws->masking_key[1] = ((uint8_t) data[i+1]) << 0;
+        ws->masking_key[2] = ((uint8_t) data[i+2]) << 0;
+        ws->masking_key[3] = ((uint8_t) data[i+3]) << 0;
+    } else {
+        ws->masking_key[0] = 0;
+        ws->masking_key[1] = 0;
+        ws->masking_key[2] = 0;
+        ws->masking_key[3] = 0;
+    }
+
+    return true;
 }
 
 // same as above, pointer type casted to unsigned
-bool ws_parse(char *data, size_t len, wsheader_type& ws) {
-	return ws_parse(reinterpret_cast<unsigned char*>(data), len, ws);
+bool ws_parse(char *data, size_t len, wsheader_type *ws) {
+    return ws_parse(reinterpret_cast<unsigned char*>(data), len, ws);
 }
 
 
 int getPort(const ftl::URI &uri) {
-	auto port = uri.getPort();
-
-	if (port == 0) {
-		if (uri.getScheme() == URI::scheme_t::SCHEME_WS) {
-			port = 80;
-		} else if (uri.getScheme() == URI::scheme_t::SCHEME_WSS) {
-			port = 443;
-		} else {
-			throw FTL_Error("Bad WS uri:" + uri.to_string());
-		}
-	}
-
-	return port;
+    auto port = uri.getPort();
+
+    if (port == 0) {
+        if (uri.getScheme() == URI::scheme_t::SCHEME_WS) {
+            port = 80;
+        } else if (uri.getScheme() == URI::scheme_t::SCHEME_WSS) {
+            port = 443;
+        } else {
+            throw FTL_Error("Bad WS uri:" + uri.to_string());
+        }
+    }
+
+    return port;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
 template<typename SocketT>
-WebSocketBase<SocketT>::WebSocketBase() {
-	
-}
+WebSocketBase<SocketT>::WebSocketBase() {}
 
 template<typename SocketT>
 void WebSocketBase<SocketT>::connect(const ftl::URI& uri, int timeout) {
-	int port = getPort(uri);
-	
-	// connect via TCP/TLS
-	if (!SocketT::connect(uri.getHost(), port, timeout)) {
-		throw FTL_Error("WS: connect() failed");
-	}
-	
-	std::string http = "";
-	int status;
-	int i;
-	char line[256];
-	
-	http += "GET " + uri.getPath() + " HTTP/1.1\r\n";
-	if (port == 80) {
-		http += "Host: " + uri.getHost() + "\r\n";
-	} else {
-		// TODO: is this correct when connecting over TLS
-		http += "Host: " + uri.getHost() + ":" 
-			 + std::to_string(port) + "\r\n";
-	}
-
-	if (uri.hasUserInfo()) {
-		http += "Authorization: Basic ";
-		http += base64_encode(uri.getUserInfo()) + "\r\n";
-		//https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization
-		if (uri.getProtocol() != URI::scheme_t::SCHEME_WSS) {
-			LOG(WARNING) << "HTTP Basic Auth is being sent without TLS";
-		}
-	}
-
-	http += "Upgrade: websocket\r\n";
-	http += "Connection: Upgrade\r\n";
-	http += "Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r\n";
-	http += "Sec-WebSocket-Version: 13\r\n";
-	http += "\r\n";
-	// TODO: check/process HTTP response code 
-
-	int rc = SocketT::send(http.c_str(), int(http.length()));
-	if (rc != (int)http.length()) {
-		throw FTL_Error("Could not send Websocket http request... (" 
-						+ std::to_string(rc) + ", "
-					 	+ std::to_string(errno) + ")\n" + http);
-	}
-	
-	for (i = 0; i < 2 || (i < 255 && line[i-2] != '\r' && line[i-1] != '\n'); ++i) {
-		if (SocketT::recv(line + i, 1) == 0) {
-			throw FTL_Error("Connection closed by remote");
-		}
-	}
-
-	line[i] = 0;
-	if (i == 255) {
-		throw FTL_Error("Got invalid status line connecting to: " + uri.getHost());
-	}
-	if (sscanf(line, "HTTP/1.1 %d", &status) != 1 || status != 101) {
-		throw FTL_Error("ERROR: Got bad status connecting to: "
-						+ uri.getHost() + ": " + line);
-	}
-
-	// TODO: verify response headers,
-	while (true) {
-		for (i = 0; i < 2 || (i < 255 && line[i-2] != '\r' && line[i-1] != '\n'); ++i) {
-			if (SocketT::recv(line+i, 1) == 0) {
-				throw FTL_Error("Connection closed by remote");
-			}
-		}
-		if (line[0] == '\r' && line[1] == '\n') { break; }
-	}
+    int port = getPort(uri);
+
+    // connect via TCP/TLS
+    if (!SocketT::connect(uri.getHost(), port, timeout)) {
+        throw FTL_Error("WS: connect() failed");
+    }
+
+    std::string http = "";
+    int status;
+    int i;
+    char line[256];
+
+    http += "GET " + uri.getPath() + " HTTP/1.1\r\n";
+    if (port == 80) {
+        http += "Host: " + uri.getHost() + "\r\n";
+    } else {
+        // TODO(Seb): is this correct when connecting over TLS
+        http += "Host: " + uri.getHost() + ":"
+             + std::to_string(port) + "\r\n";
+    }
+
+    if (uri.hasUserInfo()) {
+        http += "Authorization: Basic ";
+        http += base64_encode(uri.getUserInfo()) + "\r\n";
+        // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization
+        if (uri.getProtocol() != URI::scheme_t::SCHEME_WSS) {
+            LOG(WARNING) << "HTTP Basic Auth is being sent without TLS";
+        }
+    }
+
+    http += "Upgrade: websocket\r\n";
+    http += "Connection: Upgrade\r\n";
+    http += "Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r\n";
+    http += "Sec-WebSocket-Version: 13\r\n";
+    http += "\r\n";
+    // TODO(Seb): check/process HTTP response code
+
+    int rc = SocketT::send(http.c_str(), static_cast<int>(http.length()));
+    if (rc != static_cast<int>(http.length())) {
+        throw FTL_Error("Could not send Websocket http request... ("
+                        + std::to_string(rc) + ", "
+                         + std::to_string(errno) + ")\n" + http);
+    }
+
+    for (i = 0; i < 2 || (i < 255 && line[i-2] != '\r' && line[i-1] != '\n'); ++i) {
+        if (SocketT::recv(line + i, 1) == 0) {
+            throw FTL_Error("Connection closed by remote");
+        }
+    }
+
+    line[i] = 0;
+    if (i == 255) {
+        throw FTL_Error("Got invalid status line connecting to: " + uri.getHost());
+    }
+    if (sscanf(line, "HTTP/1.1 %d", &status) != 1 || status != 101) {
+        throw FTL_Error("ERROR: Got bad status connecting to: "
+                        + uri.getHost() + ": " + line);
+    }
+
+    // TODO(Seb): verify response headers,
+    while (true) {
+        for (i = 0; i < 2 || (i < 255 && line[i-2] != '\r' && line[i-1] != '\n'); ++i) {
+            if (SocketT::recv(line+i, 1) == 0) {
+                throw FTL_Error("Connection closed by remote");
+            }
+        }
+        if (line[0] == '\r' && line[1] == '\n') { break; }
+    }
 }
 
 template<typename SocketT>
 bool WebSocketBase<SocketT>::prepare_next(char* data, size_t data_len, size_t& offset) {
-	
-	offset = 0;
-	
-	//		 Header may be smaller than 14 bytes. If there isn't enough data,
-	//		 do not process before receiving more data.
-	if (data_len < 14) { return false; } 
-
-	wsheader_type header;
-	if (!ws_parse(data, data_len, header)) {
-		throw FTL_Error("corrupted WS header");
-	}
-
-	if ((header.N + header.header_size) > data_len) {
-		/*LOG(WARNING) << "buffered: " << data_len
-					 << ", ws frame size: " << (header.N + header.header_size)
-					 << " (not enough data in buffer)";*/ // noisy
-		return false;
-	}
-
-	if (header.mask) {
-		throw FTL_Error("masked WebSocket data not supported"); // TODO
-	}
-
-	// payload/application data/extension of control frames should be ignored?
-	// fragments are OK (data is be in order and frames are not interleaved)
-
-	offset = header.header_size;
-	return true;
+    offset = 0;
+
+    // Header may be smaller than 14 bytes. If there isn't enough data,
+    // do not process before receiving more data.
+    if (data_len < 14) { return false; }
+
+    wsheader_type header;
+    if (!ws_parse(data, data_len, &header)) {
+        throw FTL_Error("corrupted WS header");
+    }
+
+    if ((header.N + header.header_size) > data_len) {
+        /*LOG(WARNING) << "buffered: " << data_len
+                     << ", ws frame size: " << (header.N + header.header_size)
+                     << " (not enough data in buffer)"; */
+        return false;
+    }
+
+    if (header.mask) {
+        throw FTL_Error("masked WebSocket data not supported");  // TODO(Seb):
+    }
+
+    // payload/application data/extension of control frames should be ignored?
+    // fragments are OK (data is be in order and frames are not interleaved)
+
+    offset = header.header_size;
+    return true;
 }
 
 template<typename SocketT>
 ssize_t WebSocketBase<SocketT>::writev(const struct iovec *iov, int iovcnt) {
 
-	if ((iovcnt + 1) >= ssize_t(iovecs_.size())) { iovecs_.resize(iovcnt + 1); }
-	// copy iovecs to local buffer, first iovec entry reserved for header
-	std::copy(iov, iov + iovcnt, iovecs_.data() + 1);
-
-	// masking
-	size_t msglen = 0;
-	uint32_t mask = secure_rnd();
-	uint8_t* masking_key = reinterpret_cast<uint8_t*>(&mask);
-	
-	// calculate total size of message and mask it.
-	for (int i = 1; i < iovcnt + 1; i++) {
-		const size_t mlen = iovecs_[i].iov_len;
-		char *buf = (char*)iovecs_[i].iov_base;
-
-		// TODO: Make this more efficient.
-		for (size_t j = 0; j != mlen; ++j) {
-			buf[j] ^= masking_key[(msglen + j)&0x3];
-		}
-		msglen += mlen;
-	}
-
-	// create header
-	constexpr size_t h_size = 20;
-	char h_buffer[h_size];
-
-	auto rc = ws_prepare(wsheader_type::BINARY_FRAME, true, mask, msglen, h_buffer, h_size);
-	if (rc < 0) { return -1; }
-
-	// send header + data
-	iovecs_[0].iov_base = h_buffer;
-	iovecs_[0].iov_len = rc;
-
-	auto sent = SocketT::writev(iovecs_.data(), iovcnt + 1);
-	if (sent > 0) {
-		// do not report sent header size
-		return sent - rc;
-	}
-	return sent;
+    if ((iovcnt + 1) >= ssize_t(iovecs_.size())) { iovecs_.resize(iovcnt + 1); }
+    // copy iovecs to local buffer, first iovec entry reserved for header
+    std::copy(iov, iov + iovcnt, iovecs_.data() + 1);
+
+    // masking
+    size_t msglen = 0;
+    uint32_t mask = secure_rnd();
+    uint8_t* masking_key = reinterpret_cast<uint8_t*>(&mask);
+
+    // calculate total size of message and mask it.
+    for (int i = 1; i < iovcnt + 1; i++) {
+        const size_t mlen = iovecs_[i].iov_len;
+        char *buf = reinterpret_cast<char*>(iovecs_[i].iov_base);
+
+        // TODO(Seb): Make this more efficient.
+        for (size_t j = 0; j != mlen; ++j) {
+            buf[j] ^= masking_key[(msglen + j)&0x3];
+        }
+        msglen += mlen;
+    }
+
+    // create header
+    constexpr size_t kHSize = 20;
+    char h_buffer[kHSize];
+
+    auto rc = ws_prepare(wsheader_type::BINARY_FRAME, true, mask, msglen, h_buffer, kHSize);
+    if (rc < 0) { return -1; }
+
+    // send header + data
+    iovecs_[0].iov_base = h_buffer;
+    iovecs_[0].iov_len = rc;
+
+    auto sent = SocketT::writev(iovecs_.data(), iovcnt + 1);
+    if (sent > 0) {
+        // do not report sent header size
+        return sent - rc;
+    }
+    return sent;
 }
 
 template<typename SocketT>
 ftl::URI::scheme_t WebSocketBase<SocketT>::scheme() const {return ftl::URI::SCHEME_TCP; }
 
 // explicit instantiation
-template class WebSocketBase<Connection_TCP>; // Connection_WS
+template class WebSocketBase<Connection_TCP>;  // Connection_WS
 #ifdef HAVE_GNUTLS
-template class WebSocketBase<Connection_TLS>; // Connection_WSS
-#endif
\ No newline at end of file
+template class WebSocketBase<Connection_TLS>;  // Connection_WSS
+#endif
diff --git a/src/protocol/websocket.hpp b/src/protocol/websocket.hpp
index 8e73be1667d4b2996c5fa952294ed06dd629dbab..7d01503c8d0db54f4a3cf8782f999cf7c0b904d3 100644
--- a/src/protocol/websocket.hpp
+++ b/src/protocol/websocket.hpp
@@ -1,40 +1,42 @@
-#ifndef _FTL_NET_WEBSOCKET_HPP_
-#define _FTL_NET_WEBSOCKET_HPP_
+/**
+ * @file websocket.hpp
+ * @copyright Copyright (c) 2022 University of Turku, MIT License
+ * @author Sebastian Hahta
+ */
 
-#include "connection.hpp"
-#include "tcp.hpp"
-#include "tls.hpp"
+#pragma once
 
 #include <vector>
 #include <random>
 
+#include "connection.hpp"
+#include "tcp.hpp"
+#include "tls.hpp"
+
 namespace ftl {
 namespace net {
 namespace internal {
 
 template<typename SocketT>
 class WebSocketBase : public SocketT {
-public:
-	WebSocketBase();
-	ftl::URI::scheme_t scheme() const override;
-	void connect(const ftl::URI& uri, int timeout=0) override;
-
-	bool prepare_next(char* buffer, size_t len, size_t &offset) override;
+ public:
+    WebSocketBase();
+    ftl::URI::scheme_t scheme() const override;
+    void connect(const ftl::URI& uri, int timeout = 0) override;
 
-	ssize_t writev(const struct iovec *iov, int iovcnt) override;
+    bool prepare_next(char* buffer, size_t len, size_t &offset) override;
 
-protected:
+    ssize_t writev(const struct iovec *iov, int iovcnt) override;
 
-	// output io vectors (incl. header)
-	std::vector<struct iovec> iovecs_;
+ protected:
+    // output io vectors (incl. header)
+    std::vector<struct iovec> iovecs_;
 };
 
 using Connection_WS = WebSocketBase<Connection_TCP>;
 #ifdef HAVE_GNUTLS
 using Connection_WSS = WebSocketBase<Connection_TLS>;
 #endif
-}
-}
-}
-
-#endif
+}  // namespace internal
+}  // namespace net
+}  // namespace ftl
diff --git a/src/rpc.cpp b/src/rpc.cpp
index ef4a6d183a684bad91bdbc2387b1534b9956ba3d..f0c275ab17c8024f89e36466c62faf14d622255f 100644
--- a/src/rpc.cpp
+++ b/src/rpc.cpp
@@ -1,3 +1,9 @@
+/**
+ * @file rpc.cpp
+ * @copyright Copyright (c) 2022 University of Turku, MIT License
+ * @author Nicolas Pope
+ */
+
 #include "rpc.hpp"
 
 #include "streams/netstream.hpp"
diff --git a/src/rpc.hpp b/src/rpc.hpp
index 03519d067c8faf69b8641b27888cf939ae2214fc..78a65500a6d9d7ce5c067e4efb658edc1fe664be 100644
--- a/src/rpc.hpp
+++ b/src/rpc.hpp
@@ -1,3 +1,9 @@
+/**
+ * @file rpc.hpp
+ * @copyright Copyright (c) 2022 University of Turku, MIT License
+ * @author Nicolas Pope
+ */
+
 #pragma once
 
 #include <memory>
@@ -11,5 +17,5 @@ namespace rpc {
 
 void install(ftl::net::Universe *net);
 
-}
-}
+}  // namespace rpc
+}  // namespace ftl
diff --git a/src/self.cpp b/src/self.cpp
index 85e49401143ad7f86f7bfbd55d7f5f060f9458ea..4aff76ab083c220eb1ab4d4f07fad3fe7d93b548 100644
--- a/src/self.cpp
+++ b/src/self.cpp
@@ -1,3 +1,9 @@
+/**
+ * @file self.cpp
+ * @copyright Copyright (c) 2022 University of Turku, MIT License
+ * @author Nicolas Pope
+ */
+
 #include "universe.hpp"
 #include <ftl/protocol/self.hpp>
 #include "./streams/netstream.hpp"
@@ -18,7 +24,7 @@ std::shared_ptr<ftl::protocol::Stream> Self::createStream(const std::string &uri
     if (!u.isValid()) throw FTL_Error("Invalid Stream URI");
 
     switch (u.getScheme()) {
-    case ftl::URI::SCHEME_FTL   : return std::make_shared<ftl::protocol::Net>(uri, universe_.get(), true); 
+    case ftl::URI::SCHEME_FTL   : return std::make_shared<ftl::protocol::Net>(uri, universe_.get(), true);
     case ftl::URI::SCHEME_FILE  :
     case ftl::URI::SCHEME_NONE  :
     default                     : throw FTL_Error("Invalid Stream URI");
@@ -31,13 +37,13 @@ std::shared_ptr<ftl::protocol::Stream> Self::getStream(const std::string &uri) {
     if (!u.isValid()) throw FTL_Error("Invalid Stream URI");
 
     switch (u.getScheme()) {
-    case ftl::URI::SCHEME_FTL   : return std::make_shared<ftl::protocol::Net>(uri, universe_.get(), false); 
+    case ftl::URI::SCHEME_FTL   : return std::make_shared<ftl::protocol::Net>(uri, universe_.get(), false);
     case ftl::URI::SCHEME_FILE  :
     case ftl::URI::SCHEME_NONE  :
     default                     : throw FTL_Error("Invalid Stream URI");
     }
 }
-	
+
 void Self::start() {
     universe_->start();
 }
@@ -99,7 +105,11 @@ ftl::Handle Self::onDisconnect(const std::function<bool(const std::shared_ptr<ft
     });
 }
 
-ftl::Handle Self::onError(const std::function<bool(const std::shared_ptr<ftl::protocol::Node>&, ftl::protocol::Error, const std::string &)> &cb) {
+using ErrorCb = std::function<bool(
+    const std::shared_ptr<ftl::protocol::Node>&,
+    ftl::protocol::Error, const std::string &)>;
+
+ftl::Handle Self::onError(const ErrorCb &cb) {
     return universe_->onError([cb](const ftl::net::PeerPtr &p, ftl::protocol::Error e, const std::string &estr) {
         return cb(std::make_shared<ftl::protocol::Node>(p), e, estr);
     });
diff --git a/src/socket.hpp b/src/socket.hpp
index 896d4e6a9598eb562a48b7c85323b53df7ccb482..7353ae843ac4cd4f0e3cc32ffacacfa7f8df7d3d 100644
--- a/src/socket.hpp
+++ b/src/socket.hpp
@@ -13,6 +13,6 @@ namespace internal {
 class SocketConnection;
 class SocketServer;
 
-}
-}
-}
+}  // namespace internal
+}  // namespace net
+}  // namespace ftl
diff --git a/src/socket/socket.cpp b/src/socket/socket.cpp
index 511724ed3e45d55a33826e33718b7e6606d193e2..ffdf4c3c34ab6612439f133cb9ace34165ad48ca 100644
--- a/src/socket/socket.cpp
+++ b/src/socket/socket.cpp
@@ -1,3 +1,9 @@
+/**
+ * @file socket.cpp
+ * @copyright Copyright (c) 2022 University of Turku, MIT License
+ * @author Sebastian Hahta
+ */
+
 // OS specific implementations for TCP sockets
 
 #include "../socketImpl.hpp"
@@ -13,38 +19,38 @@ bool Socket::is_open() { return status_ == STATUS::OPEN; }
 bool Socket::is_closed() { return status_ == STATUS::CLOSED; }
 
 bool Socket::set_recv_buffer_size(size_t sz) {
-	int a = static_cast<int>(sz);
-	return setsockopt(SOL_SOCKET, SO_RCVBUF, (char *) &a, sizeof(int)) != -1;
+    int a = static_cast<int>(sz);
+    return setsockopt(SOL_SOCKET, SO_RCVBUF, reinterpret_cast<char*>(&a), sizeof(int)) != -1;
 }
 
 bool Socket::set_send_buffer_size(size_t sz) {
-	int a = static_cast<int>(sz);
-	return setsockopt(SOL_SOCKET, SO_SNDBUF, (char *) &a, sizeof(int)) != -1;
+    int a = static_cast<int>(sz);
+    return setsockopt(SOL_SOCKET, SO_SNDBUF, reinterpret_cast<char*>(&a), sizeof(int)) != -1;
 }
 
 size_t Socket::get_recv_buffer_size() {
-	int a = 0;
-	socklen_t optlen = sizeof(int);
-	getsockopt(SOL_SOCKET, SO_RCVBUF, (char *) &a, &optlen);
-	return a;
+    int a = 0;
+    socklen_t optlen = sizeof(int);
+    getsockopt(SOL_SOCKET, SO_RCVBUF, reinterpret_cast<char*>(&a), &optlen);
+    return a;
 }
 
 size_t Socket::get_send_buffer_size() {
-	int a = 0;
-	socklen_t optlen = sizeof(int);
-	getsockopt(SOL_SOCKET, SO_SNDBUF, (char *) &a, &optlen);
-	return a;
+    int a = 0;
+    socklen_t optlen = sizeof(int);
+    getsockopt(SOL_SOCKET, SO_SNDBUF, reinterpret_cast<char*>(&a), &optlen);
+    return a;
 }
 
 bool Socket::set_nodelay(bool val) {
-	int flags = val ? 1 : 0;
-	return setsockopt(IPPROTO_TCP, TCP_NODELAY,
-				(char *) &flags, sizeof(flags)) == 0;
+    int flags = val ? 1 : 0;
+    return setsockopt(IPPROTO_TCP, TCP_NODELAY,
+                reinterpret_cast<char*>(&flags), sizeof(flags)) == 0;
 }
 
 bool Socket::get_nodelay() {
-	int flags = 0;
-	socklen_t len = sizeof(int);
-	getsockopt(IPPROTO_TCP, TCP_NODELAY, (char *) &flags, &len);
-	return flags;
+    int flags = 0;
+    socklen_t len = sizeof(int);
+    getsockopt(IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char*>(&flags), &len);
+    return flags;
 }
\ No newline at end of file
diff --git a/src/socket/socket_linux.cpp b/src/socket/socket_linux.cpp
index 9ec8a6338cc044238f3ba1c897a64258f008e0b5..3d1b71a6e459d6bd461064f2eee4ef28a2a71d21 100644
--- a/src/socket/socket_linux.cpp
+++ b/src/socket/socket_linux.cpp
@@ -1,3 +1,9 @@
+/**
+ * @file socket_linux.cpp
+ * @copyright Copyright (c) 2022 University of Turku, MIT License
+ * @author Sebastian Hahta
+ */
+
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/uio.h>
@@ -5,7 +11,6 @@
 #include <sys/socket.h>
 #include <netdb.h>
 #include <fcntl.h>
-
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <arpa/inet.h>
@@ -19,210 +24,207 @@ using ftl::net::internal::SocketAddress;
 
 /// resolve address for OS socket calls, return true on success
 bool ftl::net::internal::resolve_inet_address(const std::string &hostname, int port, SocketAddress &address) {
-	addrinfo hints = {}, *addrs;
-
-	// TODO: use uri for hints. Fixed values used here
-	// should work as long only TCP is used.
-	hints.ai_family = AF_INET;
-	hints.ai_socktype = SOCK_STREAM;
-	hints.ai_protocol = IPPROTO_TCP;
-	
-	auto rc = getaddrinfo(hostname.c_str(), std::to_string(port).c_str(), &hints, &addrs);
-	if (rc != 0 || addrs == nullptr) return false;
-	
-	address.len = (socklen_t) addrs->ai_addrlen;
-	memcpy(&address.addr, addrs->ai_addr, address.len);
-	freeaddrinfo(addrs);
-	return true;
+    addrinfo hints = {}, *addrs;
+
+    // TODO(Seb): use uri for hints. Fixed values used here
+    // should work as long only TCP is used.
+    hints.ai_family = AF_INET;
+    hints.ai_socktype = SOCK_STREAM;
+    hints.ai_protocol = IPPROTO_TCP;
+
+    auto rc = getaddrinfo(hostname.c_str(), std::to_string(port).c_str(), &hints, &addrs);
+    if (rc != 0 || addrs == nullptr) return false;
+
+    address.len = (socklen_t) addrs->ai_addrlen;
+    memcpy(&address.addr, addrs->ai_addr, address.len);
+    freeaddrinfo(addrs);
+    return true;
 }
 
 // Socket
 
 Socket::Socket(int domain, int type, int protocol) :
-		status_(STATUS::UNCONNECTED), fd_(-1), family_(domain), err_(0) {
-
-	int retval = socket(domain, type, protocol);
+        status_(STATUS::UNCONNECTED), fd_(-1), family_(domain), err_(0) {
+    int retval = socket(domain, type, protocol);
 
-	if (retval > 0) {
-		fd_ = retval;
-	} else {
-		LOG(ERROR) << ("socket() failed");
-		throw FTL_Error("socket: " + get_error_string());
-	}
+    if (retval > 0) {
+        fd_ = retval;
+    } else {
+        LOG(ERROR) << ("socket() failed");
+        throw FTL_Error("socket: " + get_error_string());
+    }
 }
 
 bool Socket::is_valid() { return status_ != STATUS::INVALID; }
 
 ssize_t Socket::recv(char *buffer, size_t len, int flags) {
-	return ::recv(fd_, buffer, len, flags);
+    return ::recv(fd_, buffer, len, flags);
 }
 
 ssize_t Socket::send(const char* buffer, size_t len, int flags) {
-	return ::send(fd_, buffer, len, flags);
+    return ::send(fd_, buffer, len, flags);
 }
 
 ssize_t Socket::writev(const struct iovec *iov, int iovcnt) {
-	return ::writev(fd_, iov, iovcnt);
+    return ::writev(fd_, iov, iovcnt);
 }
 
 int Socket::bind(const SocketAddress &addr) {
-	auto retval = ::bind(fd_, &addr.addr, addr.len);
-	if (retval) {
-		status_ = Socket::OPEN;
-	}
-	return retval;
+    auto retval = ::bind(fd_, &addr.addr, addr.len);
+    if (retval) {
+        status_ = Socket::OPEN;
+    }
+    return retval;
 }
 
 int Socket::listen(int backlog) {
-	return ::listen(fd_, backlog);
+    return ::listen(fd_, backlog);
 }
 
 Socket Socket::accept(SocketAddress &addr) {
-	addr.len = sizeof(SocketAddress);
-	Socket socket;
-	int retval = ::accept(fd_, &(addr.addr), &(addr.len));
-	if (retval > 0) {
-		socket.status_ = STATUS::OPEN;
-		socket.fd_ = retval;
-		socket.family_ = family_;
-	} else {
-		LOG(ERROR) << "accept returned error: " << strerror(errno); 
-		socket.status_ = STATUS::INVALID;
-	}
-	return socket;
+    addr.len = sizeof(SocketAddress);
+    Socket socket;
+    int retval = ::accept(fd_, &(addr.addr), &(addr.len));
+    if (retval > 0) {
+        socket.status_ = STATUS::OPEN;
+        socket.fd_ = retval;
+        socket.family_ = family_;
+    } else {
+        LOG(ERROR) << "accept returned error: " << strerror(errno);
+        socket.status_ = STATUS::INVALID;
+    }
+    return socket;
 }
 
 int Socket::connect(const SocketAddress& address) {
-
-	int err = 0;
-	if (status_ == STATUS::UNCONNECTED) {
-		err = ::connect(fd_, &address.addr, address.len);
-		if (err == 0) {
-			status_ = STATUS::OPEN;
-			return 0;
-		}
-		else 
-		{
-			if (errno == EINPROGRESS) {
-				status_ = STATUS::OPEN;	// close() will be called by destructor
-										// add better status code?
-				return -1;
-			} else {
-				status_ = STATUS::CLOSED;
-				::close(fd_);
-			}
-		}
-	}
-	return err;
+    int err = 0;
+    if (status_ == STATUS::UNCONNECTED) {
+        err = ::connect(fd_, &address.addr, address.len);
+        if (err == 0) {
+            status_ = STATUS::OPEN;
+            return 0;
+        } else {
+            if (errno == EINPROGRESS) {
+                status_ = STATUS::OPEN;     // close() will be called by destructor
+                                            // add better status code?
+                return -1;
+            } else {
+                status_ = STATUS::CLOSED;
+                ::close(fd_);
+            }
+        }
+    }
+    return err;
 }
 
 int Socket::connect(const SocketAddress &address, int timeout) {
-	if (timeout <= 0) {
-		return connect(address);
-	}
-
-	bool blocking = is_blocking();
-	if (blocking) set_blocking(false);
-	
-	auto rc = connect(address);
-	if (rc < 0) {
-		if (errno == EINPROGRESS) {
-			fd_set myset;
-			fd_set errset; 
-			FD_ZERO(&myset); 
-			FD_SET(fd_, &myset);
-			FD_ZERO(&errset); 
-			FD_SET(fd_, &errset); 
-
-			struct timeval tv;
-			tv.tv_sec = timeout; 
-			tv.tv_usec = 0; 
-
-			rc = select(fd_+1u, NULL, &myset, &errset, &tv); 
-			if (FD_ISSET(fd_, &errset)) rc = -1;
-		}
-	}
-
-	if (blocking)
-		set_blocking(true);
-
-	if (rc < 0) {
-		::close(fd_);
-		status_ = STATUS::CLOSED;
-		LOG(ERROR) << "socket error: " << strerror(errno);
-		return rc;
-	}
-
-	return 0;
+    if (timeout <= 0) {
+        return connect(address);
+    }
+
+    bool blocking = is_blocking();
+    if (blocking) set_blocking(false);
+
+    auto rc = connect(address);
+    if (rc < 0) {
+        if (errno == EINPROGRESS) {
+            fd_set myset;
+            fd_set errset;
+            FD_ZERO(&myset);
+            FD_SET(fd_, &myset);
+            FD_ZERO(&errset);
+            FD_SET(fd_, &errset);
+
+            struct timeval tv;
+            tv.tv_sec = timeout;
+            tv.tv_usec = 0;
+
+            rc = select(fd_+1u, NULL, &myset, &errset, &tv);
+            if (FD_ISSET(fd_, &errset)) rc = -1;
+        }
+    }
+
+    if (blocking)
+        set_blocking(true);
+
+    if (rc < 0) {
+        ::close(fd_);
+        status_ = STATUS::CLOSED;
+        LOG(ERROR) << "socket error: " << strerror(errno);
+        return rc;
+    }
+
+    return 0;
 }
 
 /// Close socket (if open). Multiple calls are safe.
 bool Socket::close() {
-	if (is_valid() && status_ != STATUS::CLOSED) {
-		status_ = STATUS::CLOSED;
-		return ::close(fd_) == 0;
-	} else if (status_ != STATUS::CLOSED) {
-		LOG(INFO) << "close() on non-valid socket";
-	}
-	return false;
+    if (is_valid() && status_ != STATUS::CLOSED) {
+        status_ = STATUS::CLOSED;
+        return ::close(fd_) == 0;
+    } else if (status_ != STATUS::CLOSED) {
+        LOG(INFO) << "close() on non-valid socket";
+    }
+    return false;
 }
 
 int Socket::setsockopt(int level, int optname, const void *optval, socklen_t optlen) {
-	return ::setsockopt(fd_, level, optname, optval, optlen);
+    return ::setsockopt(fd_, level, optname, optval, optlen);
 }
 
 int Socket::getsockopt(int level, int optname, void *optval, socklen_t *optlen) {
-	return ::getsockopt(fd_, level, optname, optval, optlen);
+    return ::getsockopt(fd_, level, optname, optval, optlen);
 }
 
 void Socket::set_blocking(bool val) {
-	auto arg = fcntl(fd_, F_GETFL, NULL);
-	arg = val ? (arg | O_NONBLOCK) : (arg & ~O_NONBLOCK);
-	fcntl(fd_, F_SETFL, arg);
+    auto arg = fcntl(fd_, F_GETFL, NULL);
+    arg = val ? (arg | O_NONBLOCK) : (arg & ~O_NONBLOCK);
+    fcntl(fd_, F_SETFL, arg);
 }
 
 bool Socket::is_blocking() {
-	return fcntl(fd_, F_GETFL, NULL) & O_NONBLOCK;
+    return fcntl(fd_, F_GETFL, NULL) & O_NONBLOCK;
 }
 
 bool Socket::is_fatal(int code) {
-	int e = (code != 0) ? code : errno;
-	return !(e == EINTR || e == EWOULDBLOCK || e == EINPROGRESS);
+    int e = (code != 0) ? code : errno;
+    return !(e == EINTR || e == EWOULDBLOCK || e == EINPROGRESS);
 }
 
 std::string Socket::get_error_string(int code) {
-	return strerror((code != 0) ? code : errno);
+    return strerror((code != 0) ? code : errno);
 }
 
 // TCP socket
 
 Socket ftl::net::internal::create_tcp_socket() {
-	return Socket(AF_INET, SOCK_STREAM, 0);
+    return Socket(AF_INET, SOCK_STREAM, 0);
 }
 
-std::string ftl::net::internal::get_host(SocketAddress& addr) {
-	char hbuf[1024];
-	int err = getnameinfo(&(addr.addr), addr.len, hbuf, sizeof(hbuf), NULL, 0, NI_NAMEREQD);
-	if (err == 0) { return std::string(hbuf); }
-	else if (err == EAI_NONAME) { return ftl::net::internal::get_ip(addr); }
-	else { LOG(WARNING) << "getnameinfo(): " << gai_strerror(err) << " (" << err << ")"; }
-	return "unknown";
+std::string ftl::net::internal::get_host(const SocketAddress& addr) {
+    char hbuf[1024];
+    int err = getnameinfo(&(addr.addr), addr.len, hbuf, sizeof(hbuf), NULL, 0, NI_NAMEREQD);
+    if (err == 0) { return std::string(hbuf); }
+    else if (err == EAI_NONAME) return ftl::net::internal::get_ip(addr);
+    else
+        LOG(WARNING) << "getnameinfo(): " << gai_strerror(err) << " (" << err << ")";
+    return "unknown";
 }
 
 SocketAddress Socket::getsockname() {
-	SocketAddress addr;
-	auto* a = reinterpret_cast<struct sockaddr*>(&(addr.addr));
-	::getsockname(fd_, a, &(addr.len));
-	return addr;
+    SocketAddress addr;
+    auto* a = reinterpret_cast<struct sockaddr*>(&(addr.addr));
+    ::getsockname(fd_, a, &(addr.len));
+    return addr;
 }
 
-std::string ftl::net::internal::get_ip(SocketAddress& addr) {
-	auto* addr_in = reinterpret_cast<struct sockaddr_in*>(&(addr.addr));
-	std::string address(inet_ntoa(addr_in->sin_addr));
-	return address;
+std::string ftl::net::internal::get_ip(const SocketAddress& addr) {
+    auto* addr_in = reinterpret_cast<const sockaddr_in*>(&(addr.addr));
+    std::string address(inet_ntoa(addr_in->sin_addr));
+    return address;
 }
 
-int ftl::net::internal::get_port(SocketAddress& addr) {
-	auto* addr_in = reinterpret_cast<struct sockaddr_in*>(&(addr.addr));
-	return htons(addr_in->sin_port);
+int ftl::net::internal::get_port(const SocketAddress& addr) {
+    auto* addr_in = reinterpret_cast<const sockaddr_in*>(&(addr.addr));
+    return htons(addr_in->sin_port);
 }
diff --git a/src/socket/socket_windows.cpp b/src/socket/socket_windows.cpp
index c2beff08a58439392ebc47bb27d795ee7fb78530..c4c855995c3872a85a80826adf4c314b1c7af2eb 100644
--- a/src/socket/socket_windows.cpp
+++ b/src/socket/socket_windows.cpp
@@ -1,16 +1,22 @@
+/**
+ * @file socket_windows.cpp
+ * @copyright Copyright (c) 2022 University of Turku, MIT License
+ * @author Sebastian Hahta
+ */
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <atomic>
+#include <string>
+
 #include "../src/socket.hpp"
 
 #include <ftl/exception.hpp>
 #include <ftl/lib/loguru.hpp>
 
-#include <atomic>
-#include <winsock2.h>
-#include <ws2tcpip.h>
 
 #pragma comment(lib, "Ws2_32.lib")
 
-#include <string>
-
 // winsock2 documentation
 // https://docs.microsoft.com/en-us/windows/win32/api/winsock2/
 
@@ -18,228 +24,223 @@ using ftl::net::internal::Socket;
 using ftl::net::internal::SocketAddress;
 
 bool ftl::net::internal::resolve_inet_address(const std::string& hostname, int port, SocketAddress& address) {
-	addrinfo hints = {}, *addrs;
+    addrinfo hints = {}, *addrs;
 
-	// TODO: use uri for hints. Fixed values used here
-	// should work as long only TCP is used.
-	hints.ai_family = AF_INET;
-	hints.ai_socktype = SOCK_STREAM;
-	hints.ai_protocol = IPPROTO_TCP;
+    // TODO(Seb): use uri for hints. Fixed values used here
+    // should work as long only TCP is used.
+    hints.ai_family = AF_INET;
+    hints.ai_socktype = SOCK_STREAM;
+    hints.ai_protocol = IPPROTO_TCP;
 
-	auto rc = getaddrinfo(hostname.c_str(), std::to_string(port).c_str(), &hints, &addrs);
-	if (rc != 0 || addrs == nullptr) return false;
-	address = *((sockaddr_in*) (addrs->ai_addr));
-	freeaddrinfo(addrs);
-	return true;
+    auto rc = getaddrinfo(hostname.c_str(), std::to_string(port).c_str(), &hints, &addrs);
+    if (rc != 0 || addrs == nullptr) return false;
+    address = *(reinterpret_cast<sockaddr_in*>(addrs->ai_addr));
+    freeaddrinfo(addrs);
+    return true;
 }
 
 static std::atomic_bool is_initialized_;
 static WSAData wsaData_;
 
 Socket::Socket(int domain, int type, int protocol) :
-	status_(STATUS::UNCONNECTED), fd_(-1), family_(domain) {
-
-	if (!is_initialized_.exchange(true)) {
-		if (WSAStartup(MAKEWORD(1, 1), &wsaData_) != 0) {
-			LOG(FATAL) << "could not initialize sockets";
-			// is it possible to retry/recover?
-		}
-	}
-
-	// TODO: initialization might not be complete if called from another thread
-	fd_ = ::socket(domain, type, protocol);
-	if (fd_ == INVALID_SOCKET) {
-		err_ = WSAGetLastError();
-		throw FTL_Error("socket() failed" + get_error_string());
-	}
+    status_(STATUS::UNCONNECTED), fd_(-1), family_(domain) {
+    if (!is_initialized_.exchange(true)) {
+        if (WSAStartup(MAKEWORD(1, 1), &wsaData_) != 0) {
+            LOG(FATAL) << "could not initialize sockets";
+            // is it possible to retry/recover?
+        }
+    }
+
+    // TODO(Seb): initialization might not be complete if called from another thread
+    fd_ = ::socket(domain, type, protocol);
+    if (fd_ == INVALID_SOCKET) {
+        err_ = WSAGetLastError();
+        throw FTL_Error("socket() failed" + get_error_string());
+    }
 }
 
 bool Socket::is_valid() {
-	return fd_ != INVALID_SOCKET;
+    return fd_ != INVALID_SOCKET;
 }
 
 ssize_t Socket::recv(char* buffer, size_t len, int flags) {
-	auto err = ::recv(fd_, buffer, len, flags);
-	if (err < 0) { err_ = WSAGetLastError(); }
-	return err;
+    auto err = ::recv(fd_, buffer, len, flags);
+    if (err < 0) { err_ = WSAGetLastError(); }
+    return err;
 }
 
 ssize_t Socket::send(const char* buffer, size_t len, int flags) {
-	return ::send(fd_, buffer, len, flags);
+    return ::send(fd_, buffer, len, flags);
 }
 
 ssize_t Socket::writev(const struct iovec* iov, int iovcnt) {
+    std::vector<WSABUF> wsabuf(iovcnt);
 
-	std::vector<WSABUF> wsabuf(iovcnt);
-
-	for (int i = 0; i < iovcnt; i++) {
-		wsabuf[i].len = (ULONG)(iov[i].iov_len);
-		wsabuf[i].buf = (char*)(iov[i].iov_base);
-	}
-
-	DWORD bytessent;
-	auto err = WSASend(fd_, wsabuf.data(), static_cast<DWORD>(wsabuf.size()), (LPDWORD)&bytessent, 0, NULL, NULL);
-	if (err < 0) { err_ = WSAGetLastError(); }
-	return (err < 0) ? err : bytessent;
+    for (int i = 0; i < iovcnt; i++) {
+        wsabuf[i].len = (ULONG)(iov[i].iov_len);
+        wsabuf[i].buf = reinterpret_cast<char*>(iov[i].iov_base);
+    }
 
+    DWORD bytessent;
+    auto err = WSASend(fd_, wsabuf.data(), static_cast<DWORD>(wsabuf.size()), (LPDWORD)&bytessent, 0, NULL, NULL);
+    if (err < 0) { err_ = WSAGetLastError(); }
+    return (err < 0) ? err : bytessent;
 }
 
 int Socket::bind(const SocketAddress& addr) {
-	int retval = ::bind(fd_, (sockaddr*)(&addr), sizeof(addr));
-	if (retval == 0) {
-		status_ = STATUS::OPEN;
-		return 0;
-	}
-	else {
-		err_ = WSAGetLastError();
-		::closesocket(fd_);
-		status_ = STATUS::CLOSED;
-		fd_ = INVALID_SOCKET;
-	}
-	return -1;
+    int retval = ::bind(fd_, reinterpret_cast<const sockaddr*>(&addr), sizeof(addr));
+    if (retval == 0) {
+        status_ = STATUS::OPEN;
+        return 0;
+    } else {
+        err_ = WSAGetLastError();
+        ::closesocket(fd_);
+        status_ = STATUS::CLOSED;
+        fd_ = INVALID_SOCKET;
+    }
+    return -1;
 }
 
 int Socket::listen(int backlog) {
-	int retval = ::listen(fd_, backlog);
-	if (retval == 0) {
-		return 0;
-	}
-	else {
-		err_ = WSAGetLastError();
-		::closesocket(fd_);
-		status_ = STATUS::CLOSED;
-		fd_ = INVALID_SOCKET;
-		return retval;
-	}
+    int retval = ::listen(fd_, backlog);
+    if (retval == 0) {
+        return 0;
+    } else {
+        err_ = WSAGetLastError();
+        ::closesocket(fd_);
+        status_ = STATUS::CLOSED;
+        fd_ = INVALID_SOCKET;
+        return retval;
+    }
 }
 
 Socket Socket::accept(SocketAddress& addr) {
-	Socket socket;
-	int addrlen = sizeof(addr);
-	int retval = ::accept(fd_, (sockaddr*)(&addr), &addrlen);
-
-	if (retval > 0) {
-		socket.status_ = STATUS::OPEN;
-		socket.fd_ = retval;
-		socket.family_ = family_;
-	} else {
-		err_ = WSAGetLastError();
-		LOG(ERROR) << "accept returned error: " << get_error_string();
-		socket.status_ = STATUS::INVALID;
-	}
-	return socket;
+    Socket socket;
+    int addrlen = sizeof(addr);
+    int retval = ::accept(fd_, reinterpret_cast<sockaddr*>(&addr), &addrlen);
+
+    if (retval > 0) {
+        socket.status_ = STATUS::OPEN;
+        socket.fd_ = retval;
+        socket.family_ = family_;
+    } else {
+        err_ = WSAGetLastError();
+        LOG(ERROR) << "accept returned error: " << get_error_string();
+        socket.status_ = STATUS::INVALID;
+    }
+    return socket;
 }
 
 int Socket::connect(const SocketAddress& address) {
-	int err = 0;
-	if (status_ != STATUS::UNCONNECTED) {
-		return -1;
-	}
-	
-	err = ::connect(fd_, (sockaddr*)(&address), sizeof(SOCKADDR));
-	if (err == 0) {
-		status_ = STATUS::OPEN;
-		return 0;
-
-	} else {
-		err_ = WSAGetLastError();
-		if (err_ == EINPROGRESS) {
-			status_ = STATUS::OPEN;
-			return -1;
-		} else {
-			::closesocket(fd_);
-			status_ = STATUS::CLOSED;
-			fd_ = INVALID_SOCKET;
-		}
-	}
-	return -1;
+    int err = 0;
+    if (status_ != STATUS::UNCONNECTED) {
+        return -1;
+    }
+
+    err = ::connect(fd_, reinterpret_cast<const sockaddr*>(&address), sizeof(SOCKADDR));
+    if (err == 0) {
+        status_ = STATUS::OPEN;
+        return 0;
+
+    } else {
+        err_ = WSAGetLastError();
+        if (err_ == EINPROGRESS) {
+            status_ = STATUS::OPEN;
+            return -1;
+        } else {
+            ::closesocket(fd_);
+            status_ = STATUS::CLOSED;
+            fd_ = INVALID_SOCKET;
+        }
+    }
+    return -1;
 }
 
 int Socket::connect(const SocketAddress& address, int timeout) {
-	// connect() blocks on Windows
-	return connect(address);
+    // connect() blocks on Windows
+    return connect(address);
 }
 
 bool Socket::close() {
-	bool retval = true;
-	if (is_valid() && status_ != STATUS::CLOSED) {
-		status_ = STATUS::CLOSED;
-		retval = closesocket(fd_) == 0;
-		err_ = errno;
-	}
-	fd_ = INVALID_SOCKET;
-	return retval;
+    bool retval = true;
+    if (is_valid() && status_ != STATUS::CLOSED) {
+        status_ = STATUS::CLOSED;
+        retval = closesocket(fd_) == 0;
+        err_ = errno;
+    }
+    fd_ = INVALID_SOCKET;
+    return retval;
 }
 
 
 int Socket::setsockopt(int level, int optname, const void* optval, socklen_t optlen) {
-	return ::setsockopt(fd_, level, optname, (const char*)optval, optlen);
+    return ::setsockopt(fd_, level, optname, (const char*)optval, optlen);
 }
 
 int Socket::getsockopt(int level, int optname, void* optval, socklen_t* optlen) {
-	return ::getsockopt(fd_, level, optname, (char*)optval, optlen);
+    return ::getsockopt(fd_, level, optname, reinterpret_cast<char*>(optval), optlen);
 }
 
 void Socket::set_blocking(bool val) {
-	LOG(ERROR) << "TODO: set blocking/non-blocking";
+    LOG(ERROR) << "TODO: set blocking/non-blocking";
 }
 
 std::string Socket::get_error_string(int code) {
-	wchar_t* s = NULL;
-	FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
-		NULL, (code != 0) ? code : err_, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&s, 0, NULL);
-	if (!s) {
-		return "Unknown";
-	}
-	std::wstring ws(s);
-	std::string msg(ws.begin(), ws.end());
-	LocalFree(s);
-	return msg;
+    wchar_t* s = NULL;
+    FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+        NULL, (code != 0) ? code : err_, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&s, 0, NULL);
+    if (!s) {
+        return "Unknown";
+    }
+    std::wstring ws(s);
+    std::string msg(ws.begin(), ws.end());
+    LocalFree(s);
+    return msg;
 }
 
 bool Socket::is_fatal(int code) {
-	if (code != 0) err_ = code;
-	return !(err_ == 0 || err_ == WSAEINTR || err_ == WSAEMSGSIZE || err_ == WSAEINPROGRESS || err_ == WSAEWOULDBLOCK);
+    if (code != 0) err_ = code;
+    return !(err_ == 0 || err_ == WSAEINTR || err_ == WSAEMSGSIZE || err_ == WSAEINPROGRESS || err_ == WSAEWOULDBLOCK);
 }
 
 bool Socket::is_blocking() {
-	return false;
+    return false;
 }
 
 // TCP socket
 
 Socket ftl::net::internal::create_tcp_socket() {
-	return Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    return Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 }
 
-std::string ftl::net::internal::get_host(SocketAddress& addr) {
-	constexpr int len_max = 512;
-	char hostname[len_max];
-	char servinfo[len_max];
-	auto retval = getnameinfo((struct sockaddr*)&addr,
-		sizeof(struct sockaddr), hostname,
-		len_max, servinfo, len_max, NI_NUMERICSERV);
+std::string ftl::net::internal::get_host(const SocketAddress& addr) {
+    constexpr int kLenMax = 512;
+    char hostname[kLenMax];
+    char servinfo[kLenMax];
+    auto retval = getnameinfo((struct sockaddr*)&addr,
+        sizeof(struct sockaddr), hostname,
+        kLenMax, servinfo, kLenMax, NI_NUMERICSERV);
 
-	if (retval != 0) {
-		return "N/A";
-	} else {
-		return std::string(hostname);
-	}
+    if (retval != 0) {
+        return "N/A";
+    } else {
+        return std::string(hostname);
+    }
 }
 
 SocketAddress Socket::getsockname() {
-	SocketAddress addr;
-	socklen_t len = sizeof(SocketAddress);
-	::getsockname(fd_, (struct sockaddr *)&addr, &len);
-	return addr;
+    SocketAddress addr;
+    socklen_t len = sizeof(SocketAddress);
+    ::getsockname(fd_, (struct sockaddr *)&addr, &len);
+    return addr;
 }
 
-std::string ftl::net::internal::get_ip(SocketAddress& addr) {
-	char buf[64];
-	inet_ntop(addr.sin_family, &(addr.sin_addr), buf, sizeof(buf));
-	return std::string(buf);
+std::string ftl::net::internal::get_ip(const SocketAddress& addr) {
+    char buf[64];
+    inet_ntop(addr.sin_family, &(addr.sin_addr), buf, sizeof(buf));
+    return std::string(buf);
 }
 
-int ftl::net::internal::get_port(SocketAddress& addr) {
-	return htons(addr.sin_port);
+int ftl::net::internal::get_port(const SocketAddress& addr) {
+    return htons(addr.sin_port);
 }
diff --git a/src/socket/types.hpp b/src/socket/types.hpp
index 42fdd7dcf473eb31b8850a9796ea778d11286795..66f5a356f0f664baf89867dfc578a2c7a27179ac 100644
--- a/src/socket/types.hpp
+++ b/src/socket/types.hpp
@@ -1,5 +1,10 @@
-#ifndef _FTL_NET_SOCKETS_TYPES_HPP_
-#define _FTL_NET_SOCKETS_TYPES_HPP_
+/**
+ * @file types.hpp
+ * @copyright Copyright (c) 2022 University of Turku, MIT License
+ * @author Sebastian Hahta
+ */
+
+#pragma once
 
 #if defined(WIN32)
 // Windows
@@ -14,8 +19,8 @@ typedef SSIZE_T ssize_t;
 // defined by msgpack, do not redefine here
 /*
 typedef struct iovec {
-	void* iov_base;
-	size_t iov_len;
+    void* iov_base;
+    size_t iov_len;
 };
 */
 
@@ -39,13 +44,11 @@ typedef sockaddr_in SocketAddress;
 typedef int socket_t;
 
 struct SocketAddress {
-	socklen_t len = sizeof(struct sockaddr);
-	struct sockaddr addr;
+    socklen_t len = sizeof(struct sockaddr);
+    struct sockaddr addr;
 };
 #endif
 
-} // internal
-} // net
-} // ftl
-
-#endif //  _FTL_NET_SOCKETS_TYPES_HPP_
\ No newline at end of file
+}  // namespace internal
+}  // namespace net
+}  // namespace ftl
diff --git a/src/socketImpl.hpp b/src/socketImpl.hpp
index 91371d9f71ec81b178ee58c3f2871a19b0d3bdda..6fbdddeb6ef09bb49e672801cf06099ccc6ec69b 100644
--- a/src/socketImpl.hpp
+++ b/src/socketImpl.hpp
@@ -1,3 +1,9 @@
+/**
+ * @file socket.hpp
+ * @copyright Copyright (c) 2020 University of Turku, MIT License
+ * @author Sebastian Hahta
+ */
+
 #pragma once
 
 #include <string>
@@ -14,72 +20,71 @@ namespace internal {
  */
 
 class Socket {
-private:
-	enum STATUS { INVALID, UNCONNECTED, OPEN, CLOSED };
-	STATUS status_;
-	socket_t fd_;
-	SocketAddress addr_;
-	int family_;
-	int err_;
+ private:
+    enum STATUS { INVALID, UNCONNECTED, OPEN, CLOSED };
+    STATUS status_;
+    socket_t fd_;
+    SocketAddress addr_;
+    int family_;
+    int err_;
 
-public:
+ public:
+    Socket(int domain, int type, int protocol);
 
-	Socket(int domain, int type, int protocol);
+    bool is_valid();
+    bool is_open();
+    bool is_closed();
+    bool is_fatal(int code = 0);
 
-	bool is_valid();
-	bool is_open();
-	bool is_closed();
-	bool is_fatal(int code=0);
+    ssize_t recv(char *buffer, size_t len, int flags);
+    ssize_t send(const char* buffer, size_t len, int flags);
+    ssize_t writev(const struct iovec *iov, int iovcnt);
 
-	ssize_t recv(char *buffer, size_t len, int flags);
-	ssize_t send(const char* buffer, size_t len, int flags);
-	ssize_t writev(const struct iovec *iov, int iovcnt);
+    int bind(const SocketAddress&);
 
-	int bind(const SocketAddress&);
+    int listen(int backlog);
 
-	int listen(int backlog);
+    Socket accept(SocketAddress&);
 
-	Socket accept(SocketAddress&);
+    int connect(const SocketAddress&);
 
-	int connect(const SocketAddress&);
+    /** Connect with timeout. Timeout implemented by changing socket temporarily
+     * to non-blocking mode and using select(). Uses connect().
+     */
+    int connect(const SocketAddress& addr, int timeout);
 
-	/** Connect with timeout. Timeout implemented by changing socket temporarily
-	 * to non-blocking mode and using select(). Uses connect().
-	 */
-	int connect(const SocketAddress& addr, int timeout);
+    /// Close socket (if open). Multiple calls are safe.
+    bool close();
 
-	/// Close socket (if open). Multiple calls are safe.
-	bool close();
+    Socket() : status_(STATUS::INVALID), fd_(-1), family_(-1), err_(0) {}
 
-	Socket() : status_(STATUS::INVALID), fd_(-1), family_(-1), err_(0) {}
+    /// Get the socket file descriptor.
+    socket_t fd() const { return fd_; }
 
-	/// Get the socket file descriptor. 
-	socket_t fd() const { return fd_; }
+    bool set_recv_buffer_size(size_t sz);
 
-	bool set_recv_buffer_size(size_t sz);
+    bool set_send_buffer_size(size_t sz);
 
-	bool set_send_buffer_size(size_t sz);
+    size_t get_recv_buffer_size();
 
-	size_t get_recv_buffer_size();
+    size_t get_send_buffer_size();
 
-	size_t get_send_buffer_size();
 
+    void set_blocking(bool val);
 
-	void set_blocking(bool val);
-	
-	bool is_blocking();
+    bool is_blocking();
 
-	std::string get_error_string(int code=0);
+    std::string get_error_string(int code = 0);
 
-	// only valid for TCP sockets
-	bool set_nodelay(bool val);
-	bool get_nodelay();
+    // only valid for TCP sockets
+    bool set_nodelay(bool val);
+    bool get_nodelay();
 
-	SocketAddress getsockname();
+    SocketAddress getsockname();
 
-	// TODO: perhaps remove and implement in custom methods instead
-	int setsockopt(int level, int optname, const void *optval, socklen_t optlen);
-	int getsockopt(int level, int optname, void *optval, socklen_t *optlen);
+    // TODO(Seb): perhaps remove and implement in custom methods instead
+    int setsockopt(int level, int optname, const void *optval, socklen_t optlen);
+    int getsockopt(int level, int optname, void *optval, socklen_t *optlen);
 };
 
 Socket create_tcp_socket();
@@ -88,11 +93,11 @@ Socket create_tcp_socket();
 bool resolve_inet_address(const std::string &hostname, int port, SocketAddress& address);
 // add new functions for other socket types
 
-// TODO assumes ipv4, add protocol info to SocketAddress structure?
-std::string get_ip(SocketAddress& address);
-std::string get_host(SocketAddress& address);
-int get_port(SocketAddress& address);
+// TODO(Seb): assumes ipv4, add protocol info to SocketAddress structure?
+std::string get_ip(const SocketAddress& address);
+std::string get_host(const SocketAddress& address);
+int get_port(const SocketAddress& address);
 
-} // namespace internal
-} // namespace net
-} // namespace ftl
+}  // namespace internal
+}  // namespace net
+}  // namespace ftl
diff --git a/src/streams/broadcaster.cpp b/src/streams/broadcaster.cpp
index 96a017406a9ea199dd2fcbac6300c02d973a7fda..5afb6c3e895accc2cb3c6118fbdce61e0b29d183 100644
--- a/src/streams/broadcaster.cpp
+++ b/src/streams/broadcaster.cpp
@@ -1,3 +1,9 @@
+/**
+ * @file broadcaster.cpp
+ * @copyright Copyright (c) 2022 University of Turku, MIT License
+ * @author Nicolas Pope
+ */
+
 #include <ftl/protocol/broadcaster.hpp>
 
 using ftl::protocol::Broadcast;
@@ -6,148 +12,138 @@ using ftl::protocol::Packet;
 using ftl::protocol::Channel;
 using ftl::protocol::FrameID;
 
-Broadcast::Broadcast() {
-
-}
+Broadcast::Broadcast() {}
 
-Broadcast::~Broadcast() {
-
-}
+Broadcast::~Broadcast() {}
 
 void Broadcast::add(const std::shared_ptr<Stream> &s) {
-	UNIQUE_LOCK(mtx_,lk);
+    UNIQUE_LOCK(mtx_, lk);
 
-	auto &entry = streams_.emplace_back();
-	entry.stream = s;
+    auto &entry = streams_.emplace_back();
+    entry.stream = s;
 
-	entry.handle = std::move(s->onPacket([this,s](const StreamPacket &spkt, const Packet &pkt) {
-		trigger(spkt, pkt);
-		return true;
-	}));
+    entry.handle = std::move(s->onPacket([this, s](const StreamPacket &spkt, const Packet &pkt) {
+        trigger(spkt, pkt);
+        return true;
+    }));
 
-	entry.avail_handle = std::move(s->onAvailable([this,s](FrameID id, Channel channel) {
-		seen(id, channel);
-		return true;
-	}));
+    entry.avail_handle = std::move(s->onAvailable([this, s](FrameID id, Channel channel) {
+        seen(id, channel);
+        return true;
+    }));
 
-	entry.req_handle = std::move(s->onRequest([this,s](const ftl::protocol::Request &req) {
-		request(req);
-		return true;
-	}));
+    entry.req_handle = std::move(s->onRequest([this, s](const ftl::protocol::Request &req) {
+        request(req);
+        return true;
+    }));
 }
 
 void Broadcast::remove(const std::shared_ptr<Stream> &s) {
-	UNIQUE_LOCK(mtx_,lk);
-	for (auto it = streams_.begin(); it != streams_.end(); ++it) {
-		if (it->stream == s) {
-			it->handle.cancel();
-			it->req_handle.cancel();
-			it->avail_handle.cancel();
-			streams_.erase(it);
-			break;
-		}
-	}
+    UNIQUE_LOCK(mtx_, lk);
+    for (auto it = streams_.begin(); it != streams_.end(); ++it) {
+        if (it->stream == s) {
+            it->handle.cancel();
+            it->req_handle.cancel();
+            it->avail_handle.cancel();
+            streams_.erase(it);
+            break;
+        }
+    }
 }
 
 void Broadcast::clear() {
-	UNIQUE_LOCK(mtx_,lk);
-	streams_.clear();
+    UNIQUE_LOCK(mtx_, lk);
+    streams_.clear();
 }
 
 bool Broadcast::post(const StreamPacket &spkt, const Packet &pkt) {
-	//SHARED_LOCK(mtx_, lk);
-
-	bool status = true;
-	for (auto &s : streams_) {
-		status = s.stream->post(spkt, pkt) && status;
-	}
-	return status;
+    bool status = true;
+    for (auto &s : streams_) {
+        status = s.stream->post(spkt, pkt) && status;
+    }
+    return status;
 }
 
 bool Broadcast::begin() {
-	bool r = true;
-	for (auto &s : streams_) {
-		r = r && s.stream->begin();
-	}
-	return r;
+    bool r = true;
+    for (auto &s : streams_) {
+        r = r && s.stream->begin();
+    }
+    return r;
 }
 
 bool Broadcast::end() {
-	bool r = true;
-	for (auto &s : streams_) {
-		r = r && s.stream->end();
-	}
-	return r;
+    bool r = true;
+    for (auto &s : streams_) {
+        r = r && s.stream->end();
+    }
+    return r;
 }
 
 bool Broadcast::active() {
-	if (streams_.size() == 0) return false;
-	bool r = true;
-	for (auto &s : streams_) {
-		r = r && s.stream->active();
-	}
-	return r;
+    if (streams_.size() == 0) return false;
+    bool r = true;
+    for (auto &s : streams_) {
+        r = r && s.stream->active();
+    }
+    return r;
 }
 
 void Broadcast::reset() {
-	SHARED_LOCK(mtx_, lk);
-	for (auto &s : streams_) {
-		s.stream->reset();
-	}
+    SHARED_LOCK(mtx_, lk);
+    for (auto &s : streams_) {
+        s.stream->reset();
+    }
 }
 
-void Broadcast::refresh() {
-
-}
+void Broadcast::refresh() {}
 
 bool Broadcast::enable(FrameID id) {
-	bool r = false;
-	{
-		SHARED_LOCK(mtx_, lk);
-		for (auto &s : streams_) {
-			r = s.stream->enable(id) || r;
-		};
-	}
-	if (r) Stream::enable(id);
-	return r;
+    bool r = false;
+    {
+        SHARED_LOCK(mtx_, lk);
+        for (auto &s : streams_) {
+            r = s.stream->enable(id) || r;
+        }
+    }
+    if (r) Stream::enable(id);
+    return r;
 }
 
 bool Broadcast::enable(FrameID id, ftl::protocol::Channel channel) {
-	bool r = false;
-	{
-		SHARED_LOCK(mtx_, lk);
-		for (auto &s : streams_) {
-			r = s.stream->enable(id, channel) || r;
-		};
-	}
-	if (r) Stream::enable(id, channel);
-	return r;
+    bool r = false;
+    {
+        SHARED_LOCK(mtx_, lk);
+        for (auto &s : streams_) {
+            r = s.stream->enable(id, channel) || r;
+        }
+    }
+    if (r) Stream::enable(id, channel);
+    return r;
 }
 
 bool Broadcast::enable(FrameID id, const ftl::protocol::ChannelSet &channels) {
-	bool r = false;
-	{
-		SHARED_LOCK(mtx_, lk);
-		for (auto &s : streams_) {
-			r = s.stream->enable(id, channels) || r;
-		};
-	}
-	if (r) Stream::enable(id, channels);
-	return r;
+    bool r = false;
+    {
+        SHARED_LOCK(mtx_, lk);
+        for (auto &s : streams_) {
+            r = s.stream->enable(id, channels) || r;
+        }
+    }
+    if (r) Stream::enable(id, channels);
+    return r;
 }
 
-void Broadcast::setProperty(ftl::protocol::StreamProperty opt, std::any value) {
-
-}
+void Broadcast::setProperty(ftl::protocol::StreamProperty opt, std::any value) {}
 
 std::any Broadcast::getProperty(ftl::protocol::StreamProperty opt) {
-	return 0;
+    return 0;
 }
 
 bool Broadcast::supportsProperty(ftl::protocol::StreamProperty opt) {
-	return false;
+    return false;
 }
 
 ftl::protocol::StreamType Broadcast::type() const {
-	return ftl::protocol::StreamType::kUnknown;
+    return ftl::protocol::StreamType::kUnknown;
 }
diff --git a/src/streams/muxer.cpp b/src/streams/muxer.cpp
index f790b12ce33564822428a365ca0c5abc9505edea..a3ec9ad753de61e6f45d439106bac93a73cef438 100644
--- a/src/streams/muxer.cpp
+++ b/src/streams/muxer.cpp
@@ -1,3 +1,9 @@
+/**
+ * @file muxer.cpp
+ * @copyright Copyright (c) 2022 University of Turku, MIT License
+ * @author Nicolas Pope
+ */
+
 #include <ftl/protocol/muxer.hpp>
 #include <ftl/lib/loguru.hpp>
 
@@ -7,223 +13,220 @@ using ftl::protocol::StreamPacket;
 using ftl::protocol::FrameID;
 using ftl::protocol::StreamType;
 
-Muxer::Muxer() {
-
-}
+Muxer::Muxer() {}
 
 Muxer::~Muxer() {
-	UNIQUE_LOCK(mutex_,lk);
-	for (auto &se : streams_) {
-		se.handle.cancel();
-		se.req_handle.cancel();
-		se.avail_handle.cancel();
-	}
+    UNIQUE_LOCK(mutex_, lk);
+    for (auto &se : streams_) {
+        se.handle.cancel();
+        se.req_handle.cancel();
+        se.avail_handle.cancel();
+    }
 }
 
 FrameID Muxer::_mapFromInput(Muxer::StreamEntry *s, FrameID id) {
-	SHARED_LOCK(mutex_,lk);
-	int64_t iid = (int64_t(s->id) << 32) | id.id;
-	auto it = imap_.find(iid);
-	if (it != imap_.end()) {
-		return it->second;
-	} else {
-		// Otherwise allocate something.
-		lk.unlock();
-		UNIQUE_LOCK(mutex_,ulk);
-
-		FrameID newID;
-		if (s->fixed_fs >= 0) {
-			int source = sourcecount_[s->fixed_fs]++;
-			newID = FrameID(s->fixed_fs, source);
-		} else {
-			int fsiid = (s->id << 16) | id.frameset();
-			if (fsmap_.count(fsiid) == 0) fsmap_[fsiid] = framesets_++;
-			newID = FrameID(fsmap_[fsiid], id.source());
-		}
-
-		imap_[iid] = newID;
-		auto &op = omap_[newID];
-		op.first = id;
-		op.second = s;
-		//LOG(INFO) << "ADD MAPPING " << newID.frameset() << " - " << newID.source();
-		return newID;
-	}
+    SHARED_LOCK(mutex_, lk);
+    int64_t iid = (int64_t(s->id) << 32) | id.id;
+    auto it = imap_.find(iid);
+    if (it != imap_.end()) {
+        return it->second;
+    } else {
+        // Otherwise allocate something.
+        lk.unlock();
+        UNIQUE_LOCK(mutex_, ulk);
+
+        FrameID newID;
+        if (s->fixed_fs >= 0) {
+            int source = sourcecount_[s->fixed_fs]++;
+            newID = FrameID(s->fixed_fs, source);
+        } else {
+            int fsiid = (s->id << 16) | id.frameset();
+            if (fsmap_.count(fsiid) == 0) fsmap_[fsiid] = framesets_++;
+            newID = FrameID(fsmap_[fsiid], id.source());
+        }
+
+        imap_[iid] = newID;
+        auto &op = omap_[newID];
+        op.first = id;
+        op.second = s;
+        return newID;
+    }
 }
 
 std::pair<FrameID, Muxer::StreamEntry*> Muxer::_mapToOutput(FrameID id) const {
-	SHARED_LOCK(mutex_,lk);	
-	auto it = omap_.find(id);
-	if (it != omap_.end()) {
-		return it->second;
-	} else {
-		// Bad
-		//LOG(ERROR) << "NO OUTPUT MAPPING " << id.frameset() << " - " << id.source();
-		return {id, nullptr};
-	}
+    SHARED_LOCK(mutex_, lk);
+    auto it = omap_.find(id);
+    if (it != omap_.end()) {
+        return it->second;
+    } else {
+        return {id, nullptr};
+    }
 }
 
 void Muxer::add(const std::shared_ptr<Stream> &s, int fsid) {
-	UNIQUE_LOCK(mutex_,lk);
-
-	auto &se = streams_.emplace_back();
-	se.id = stream_ids_++;
-	se.stream = s;
-	se.fixed_fs = fsid;
-	Muxer::StreamEntry *ptr = &se;
-
-	se.handle = std::move(s->onPacket([this,ptr](const StreamPacket &spkt, const Packet &pkt) {
-		FrameID newID = _mapFromInput(ptr, FrameID(spkt.streamID, spkt.frame_number));
-	
-		StreamPacket spkt2 = spkt;
-		spkt2.streamID = newID.frameset();
-		spkt2.frame_number = newID.source();
-
-		trigger(spkt2, pkt);
-		return true;
-	}));
-
-	se.avail_handle = std::move(s->onAvailable([this,ptr](FrameID id, Channel channel) {
-		FrameID newID = _mapFromInput(ptr, id);
-		seen(newID, channel);
-		return true;
-	}));
-
-	se.req_handle = std::move(s->onRequest([this,ptr](const Request &req) {
-		FrameID newID = _mapFromInput(ptr, req.id);
-		Request newRequest = req;
-		newRequest.id = newID;
-		request(newRequest);
-		return true;
-	}));
-
-	se.err_handle = std::move(s->onError([this](ftl::protocol::Error err, const std::string &str) {
-		error(err, str);
-		return true;
-	}));
+    UNIQUE_LOCK(mutex_, lk);
+
+    auto &se = streams_.emplace_back();
+    se.id = stream_ids_++;
+    se.stream = s;
+    se.fixed_fs = fsid;
+    Muxer::StreamEntry *ptr = &se;
+
+    se.handle = std::move(s->onPacket([this, ptr](const StreamPacket &spkt, const Packet &pkt) {
+        FrameID newID = _mapFromInput(ptr, FrameID(spkt.streamID, spkt.frame_number));
+
+        StreamPacket spkt2 = spkt;
+        spkt2.streamID = newID.frameset();
+        spkt2.frame_number = newID.source();
+
+        trigger(spkt2, pkt);
+        return true;
+    }));
+
+    se.avail_handle = std::move(s->onAvailable([this, ptr](FrameID id, Channel channel) {
+        FrameID newID = _mapFromInput(ptr, id);
+        seen(newID, channel);
+        return true;
+    }));
+
+    se.req_handle = std::move(s->onRequest([this, ptr](const Request &req) {
+        FrameID newID = _mapFromInput(ptr, req.id);
+        Request newRequest = req;
+        newRequest.id = newID;
+        request(newRequest);
+        return true;
+    }));
+
+    se.err_handle = std::move(s->onError([this](ftl::protocol::Error err, const std::string &str) {
+        error(err, str);
+        return true;
+    }));
 }
 
 void Muxer::remove(const std::shared_ptr<Stream> &s) {
-	UNIQUE_LOCK(mutex_,lk);
-	for (auto i = streams_.begin(); i != streams_.end(); ++i) {
-		if (i->stream == s) {
-			auto *se = &(*i);
-
-			se->handle.cancel();
-			se->req_handle.cancel();
-			se->avail_handle.cancel();
-
-			// Cleanup imap and omap
-			for (auto j = imap_.begin(); j != imap_.end();) {
-				const auto &e = *j;
-				if (e.first >> 32 == se->id) j = imap_.erase(j);
-				else ++j; 
-			}
-			for (auto j = omap_.begin(); j != omap_.end();) {
-				const auto &e = *j;
-				if (e.second.second == se) j = omap_.erase(j);
-				else ++j; 
-			}
-
-			streams_.erase(i);
-			return;
-		}
-	}
+    UNIQUE_LOCK(mutex_, lk);
+    for (auto i = streams_.begin(); i != streams_.end(); ++i) {
+        if (i->stream == s) {
+            auto *se = &(*i);
+
+            se->handle.cancel();
+            se->req_handle.cancel();
+            se->avail_handle.cancel();
+
+            // Cleanup imap and omap
+            for (auto j = imap_.begin(); j != imap_.end();) {
+                const auto &e = *j;
+                if (e.first >> 32 == se->id) j = imap_.erase(j);
+                else
+                    ++j;
+            }
+            for (auto j = omap_.begin(); j != omap_.end();) {
+                const auto &e = *j;
+                if (e.second.second == se) j = omap_.erase(j);
+                else
+                    ++j;
+            }
+
+            streams_.erase(i);
+            return;
+        }
+    }
 }
 
 std::shared_ptr<Stream> Muxer::originStream(FrameID id) const {
-	auto p = _mapToOutput(id);
-	return (p.second) ? p.second->stream : nullptr;
+    auto p = _mapToOutput(id);
+    return (p.second) ? p.second->stream : nullptr;
 }
 
 bool Muxer::post(const StreamPacket &spkt, const Packet &pkt) {
-	auto p = _mapToOutput(FrameID(spkt.streamID, spkt.frame_number));
-	if (!p.second) return false;
-	StreamPacket spkt2 = spkt;
-	spkt2.streamID = p.first.frameset();
-	spkt2.frame_number = p.first.source();
-	return p.second->stream->post(spkt2, pkt);
+    auto p = _mapToOutput(FrameID(spkt.streamID, spkt.frame_number));
+    if (!p.second) return false;
+    StreamPacket spkt2 = spkt;
+    spkt2.streamID = p.first.frameset();
+    spkt2.frame_number = p.first.source();
+    return p.second->stream->post(spkt2, pkt);
 }
 
 bool Muxer::begin() {
-	bool r = true;
-	for (auto &s : streams_) {
-		r = r && s.stream->begin();
-	}
-	return r;
+    bool r = true;
+    for (auto &s : streams_) {
+        r = r && s.stream->begin();
+    }
+    return r;
 }
 
 bool Muxer::end() {
-	bool r = true;
-	for (auto &s : streams_) {
-		r = r && s.stream->end();
-	}
-	return r;
+    bool r = true;
+    for (auto &s : streams_) {
+        r = r && s.stream->end();
+    }
+    return r;
 }
 
 bool Muxer::active() {
-	bool r = true;
-	for (auto &s : streams_) {
-		r = r && s.stream->active();
-	}
-	return r;
+    bool r = true;
+    for (auto &s : streams_) {
+        r = r && s.stream->active();
+    }
+    return r;
 }
 
 void Muxer::reset() {
-	for (auto &s : streams_) {
-		s.stream->reset();
-	}
+    for (auto &s : streams_) {
+        s.stream->reset();
+    }
 }
 
 bool Muxer::enable(FrameID id) {
-	auto p = _mapToOutput(id);
-	if (!p.second) return false;
-	bool r = p.second->stream->enable(p.first);
-	if (r) Stream::enable(id);
-	return r;
+    auto p = _mapToOutput(id);
+    if (!p.second) return false;
+    bool r = p.second->stream->enable(p.first);
+    if (r) Stream::enable(id);
+    return r;
 }
 
 bool Muxer::enable(FrameID id, ftl::protocol::Channel channel) {
-	auto p = _mapToOutput(id);
-	if (!p.second) return false;
-	bool r = p.second->stream->enable(p.first, channel);
-	if (r) Stream::enable(id, channel);
-	return r;
+    auto p = _mapToOutput(id);
+    if (!p.second) return false;
+    bool r = p.second->stream->enable(p.first, channel);
+    if (r) Stream::enable(id, channel);
+    return r;
 }
 
 bool Muxer::enable(FrameID id, const ftl::protocol::ChannelSet &channels) {
-	auto p = _mapToOutput(id);
-	if (!p.second) return false;
-	bool r = p.second->stream->enable(p.first, channels);
-	if (r) Stream::enable(id, channels);
-	return r;
+    auto p = _mapToOutput(id);
+    if (!p.second) return false;
+    bool r = p.second->stream->enable(p.first, channels);
+    if (r) Stream::enable(id, channels);
+    return r;
 }
 
 void Muxer::setProperty(ftl::protocol::StreamProperty opt, std::any value) {
-	for (auto &s : streams_) {
-		s.stream->setProperty(opt, value);
-	}
+    for (auto &s : streams_) {
+        s.stream->setProperty(opt, value);
+    }
 }
 
 std::any Muxer::getProperty(ftl::protocol::StreamProperty opt) {
-	for (auto &s : streams_) {
-		if (s.stream->supportsProperty(opt)) return s.stream->getProperty(opt);
-	}
-	return 0;
+    for (auto &s : streams_) {
+        if (s.stream->supportsProperty(opt)) return s.stream->getProperty(opt);
+    }
+    return 0;
 }
 
 bool Muxer::supportsProperty(ftl::protocol::StreamProperty opt) {
-	for (auto &s : streams_) {
-		if (s.stream->supportsProperty(opt)) return true;
-	}
-	return false;
+    for (auto &s : streams_) {
+        if (s.stream->supportsProperty(opt)) return true;
+    }
+    return false;
 }
 
 StreamType Muxer::type() const {
-	StreamType t = StreamType::kUnknown;
-	for (const auto &s : streams_) {
-		const StreamType tt = s.stream->type();
-		if (t == StreamType::kUnknown) t = tt;
-		else if (t != tt) t = StreamType::kMixed;
-	}
-	return t;
+    StreamType t = StreamType::kUnknown;
+    for (const auto &s : streams_) {
+        const StreamType tt = s.stream->type();
+        if (t == StreamType::kUnknown) t = tt;
+        else if (t != tt) t = StreamType::kMixed;
+    }
+    return t;
 }
diff --git a/src/streams/netstream.cpp b/src/streams/netstream.cpp
index 128eebcb2ac1c1fcf45a579e98996275b212697e..a780bfc18a1fd4fc08a3f8ad628677438b4b07b4 100644
--- a/src/streams/netstream.cpp
+++ b/src/streams/netstream.cpp
@@ -1,5 +1,12 @@
+/**
+ * @file netstream.cpp
+ * @copyright Copyright (c) 2022 University of Turku, MIT License
+ * @author Nicolas Pope
+ */
+
+#include <list>
+#include <string>
 #include "netstream.hpp"
-//#include "adaptive.hpp"
 #include <ftl/time.hpp>
 #include "packetMsgpack.hpp"
 
@@ -26,6 +33,9 @@ using ftl::protocol::kAllFramesets;
 using ftl::protocol::StreamProperty;
 using std::string;
 using std::optional;
+using std::chrono::time_point_cast;
+using std::chrono::milliseconds;
+using std::chrono::high_resolution_clock;
 
 std::atomic_size_t Net::req_bitrate__ = 0;
 std::atomic_size_t Net::tx_bitrate__ = 0;
@@ -38,512 +48,520 @@ static std::list<std::string> net_streams;
 static SHARED_MUTEX stream_mutex;
 
 void Net::installRPC(ftl::net::Universe *net) {
-	net->bind("find_stream", [net](const std::string &uri) -> optional<ftl::UUID> {
-		DLOG(INFO) << "Request for stream: " << uri;
-
-		ftl::URI u1(uri);
-		std::string base = u1.getBaseURI();
-
-		SHARED_LOCK(stream_mutex, lk);
-		for (const auto &s : net_streams) {
-			ftl::URI u2(s);
-			// Don't compare query string components.
-			if (base == u2.getBaseURI()) {
-				return net->id();
-			}
-		}
-		return {};
-	});
-
-	net->bind("list_streams", []() {
-		SHARED_LOCK(stream_mutex, lk);
-		return net_streams;
-	});
-
-	net->bind("enable_stream", [](const std::string &uri, unsigned int fsid, unsigned int fid) {
-		// Nothing to do here, used by web service
-	});
-
-	net->bind("add_stream", [](const std::string &uri) {
-		// TODO: Trigger some callback
-	});
-
-	// TODO: Call "list_streams" to get all available locally
-	// This call should be done on any Peer connection
-	// and perhaps periodically
+    net->bind("find_stream", [net](const std::string &uri) -> optional<ftl::UUID> {
+        DLOG(INFO) << "Request for stream: " << uri;
+
+        ftl::URI u1(uri);
+        std::string base = u1.getBaseURI();
+
+        SHARED_LOCK(stream_mutex, lk);
+        for (const auto &s : net_streams) {
+            ftl::URI u2(s);
+            // Don't compare query string components.
+            if (base == u2.getBaseURI()) {
+                return std::reference_wrapper(net->id());
+            }
+        }
+        return {};
+    });
+
+    net->bind("list_streams", []() {
+        SHARED_LOCK(stream_mutex, lk);
+        return net_streams;
+    });
+
+    net->bind("enable_stream", [](const std::string &uri, unsigned int fsid, unsigned int fid) {
+        // Nothing to do here, used by web service
+    });
+
+    net->bind("add_stream", [](const std::string &uri) {
+        // TODO(Nick): Trigger some callback
+    });
+
+    // TODO(Nick): Call "list_streams" to get all available locally
+    // This call should be done on any Peer connection
+    // and perhaps periodically
 }
 
 Net::Net(const std::string &uri, ftl::net::Universe *net, bool host) :
-		net_(net), time_peer_(ftl::UUID(0)), uri_(uri), host_(host) {
-
-	ftl::URI u(uri_);
-	if (!u.isValid() || !(u.getScheme() == ftl::URI::SCHEME_FTL)) {
-		error(Error::kBadURI, uri_);
-		throw FTL_Error("Bad stream URI");
-	}
-	base_uri_ = u.getBaseURI();
-
-	if (host_) {
-		// Automatically set name
-		name_.resize(1024);
-		#ifdef WIN32
-		DWORD size = name_.capacity();
-		GetComputerName(name_.data(), &size);
-		#else
-		gethostname(name_.data(), name_.capacity());
-		#endif
-	} else {
-		name_ = "No name";
-	}
+        net_(net), time_peer_(ftl::UUID(0)), uri_(uri), host_(host) {
+    ftl::URI u(uri_);
+    if (!u.isValid() || !(u.getScheme() == ftl::URI::SCHEME_FTL)) {
+        error(Error::kBadURI, uri_);
+        throw FTL_Error("Bad stream URI");
+    }
+    base_uri_ = u.getBaseURI();
+
+    if (host_) {
+        // Automatically set name
+        name_.resize(1024);
+        #ifdef WIN32
+        DWORD size = name_.capacity();
+        GetComputerName(name_.data(), &size);
+        #else
+        gethostname(name_.data(), name_.capacity());
+        #endif
+    } else {
+        name_ = "No name";
+    }
 }
 
 Net::~Net() {
-	end();
+    end();
 
-	// FIXME: Wait to ensure no net callbacks are active.
-	// Do something better than this
-	std::this_thread::sleep_for(std::chrono::milliseconds(10));
+    // FIXME: Wait to ensure no net callbacks are active.
+    // Do something better than this
+    std::this_thread::sleep_for(std::chrono::milliseconds(10));
 }
 
 bool Net::post(const StreamPacket &spkt, const Packet &pkt) {
-	if (!active_) return false;
-	if (paused_) return true;
-	bool hasStale = false;
-
-	// Cast to include msgpack methods
-	auto spkt_net = reinterpret_cast<const StreamPacketMSGPACK&>(spkt);
-
-	// Version of packet without data but with msgpack methods
-	PacketMSGPACK pkt_strip;
-	pkt_strip.codec = pkt.codec;
-	pkt_strip.bitrate = pkt.bitrate;
-	pkt_strip.frame_count = pkt.frame_count;
-	pkt_strip.flags = pkt.flags;
-
-	if (host_) {
-		SHARED_LOCK(mutex_,lk);
-		for (auto &client : clients_) {
-			// Strip packet data if channel is not wanted by client
-			const bool strip = int(spkt.channel) < 32 && pkt.data.size() > 0 && ((1 << int(spkt.channel)) & client.channels) == 0;
-
-			try {
-				short pre_transmit_latency = short(ftl::time::get_time() - spkt.localTimestamp);
-
-				// TODO: msgpack only once and broadcast.
-				// TODO: send in parallel and then wait on all futures?
-				// Or send non-blocking and wait
-				if (!net_->send(client.peerid,
-						base_uri_,
-						pre_transmit_latency,  // Time since timestamp for tx
-						spkt_net,
-						(strip) ? pkt_strip : reinterpret_cast<const PacketMSGPACK&>(pkt))) {
-
-					// Send failed so mark as client stream completed
-					client.txcount = client.txmax;
-				} else {
-					if (!strip && pkt.data.size() > 0) _checkTXRate(pkt.data.size(), 0, spkt.timestamp);
-
-					// Count frame as completed only if last block and channel is 0
-					// FIXME: This is unreliable, colour might not exist etc.
-					if (spkt_net.streamID == 0 && spkt.frame_number == 0 && spkt.channel == Channel::kColour) ++client.txcount;
-				}
-			} catch(...) {
-				client.txcount = client.txmax;
-			}
-
-			if (client.txcount >= client.txmax) {
-				hasStale = true;
-			}
-		}
-	} else {
-		try {
-			short pre_transmit_latency = short(ftl::time::get_time() - spkt.localTimestamp);
-
-			if (!net_->send(*peer_,
-					base_uri_,
-					pre_transmit_latency,  // Time since timestamp for tx
-					spkt_net,
-					reinterpret_cast<const PacketMSGPACK&>(pkt))) {
-
-			}
-			if (pkt.data.size() > 0) _checkTXRate(pkt.data.size(), 0, spkt.timestamp);
-		} catch(...) {
-			// TODO: Some disconnect error
-			return false;
-		}
-	}
-
-	if (hasStale) _cleanUp();
-
-	hasPosted(spkt, pkt);
-
-	return true;
+    if (!active_) return false;
+    if (paused_) return true;
+    bool hasStale = false;
+
+    // Cast to include msgpack methods
+    auto spkt_net = reinterpret_cast<const StreamPacketMSGPACK&>(spkt);
+
+    // Version of packet without data but with msgpack methods
+    PacketMSGPACK pkt_strip;
+    pkt_strip.codec = pkt.codec;
+    pkt_strip.bitrate = pkt.bitrate;
+    pkt_strip.frame_count = pkt.frame_count;
+    pkt_strip.flags = pkt.flags;
+
+    if (host_) {
+        SHARED_LOCK(mutex_, lk);
+        for (auto &client : clients_) {
+            // Strip packet data if channel is not wanted by client
+            const bool strip =
+                static_cast<int>(spkt.channel) < 32 && pkt.data.size() > 0
+                && ((1 << static_cast<int>(spkt.channel)) & client.channels) == 0;
+
+            try {
+                int16_t pre_transmit_latency = int16_t(ftl::time::get_time() - spkt.localTimestamp);
+
+                // TODO(Nick): msgpack only once and broadcast.
+                // TODO(Nick): send in parallel and then wait on all futures?
+                // Or send non-blocking and wait
+                if (!net_->send(client.peerid,
+                        base_uri_,
+                        pre_transmit_latency,  // Time since timestamp for tx
+                        spkt_net,
+                        (strip) ? pkt_strip : reinterpret_cast<const PacketMSGPACK&>(pkt))) {
+                    // Send failed so mark as client stream completed
+                    client.txcount = client.txmax;
+                } else {
+                    if (!strip && pkt.data.size() > 0) _checkTXRate(pkt.data.size(), 0, spkt.timestamp);
+
+                    // Count frame as completed only if last block and channel is 0
+                    // FIXME: This is unreliable, colour might not exist etc.
+                    if (spkt_net.streamID == 0 && spkt.frame_number == 0 && spkt.channel == Channel::kColour) {
+                        ++client.txcount;
+                    }
+                }
+            } catch(...) {
+                client.txcount = client.txmax;
+            }
+
+            if (client.txcount >= client.txmax) {
+                hasStale = true;
+            }
+        }
+    } else {
+        try {
+            int16_t pre_transmit_latency = int16_t(ftl::time::get_time() - spkt.localTimestamp);
+
+            net_->send(*peer_,
+                base_uri_,
+                pre_transmit_latency,  // Time since timestamp for tx
+                spkt_net,
+                reinterpret_cast<const PacketMSGPACK&>(pkt));
+
+            if (pkt.data.size() > 0) _checkTXRate(pkt.data.size(), 0, spkt.timestamp);
+        } catch(...) {
+            // TODO(Nick): Some disconnect error
+            return false;
+        }
+    }
+
+    if (hasStale) _cleanUp();
+
+    hasPosted(spkt, pkt);
+
+    return true;
 }
 
-void Net::_processPacket(ftl::net::Peer *p, short ttimeoff, const StreamPacket &spkt_raw, const Packet &pkt) {
-	int64_t now = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now()).time_since_epoch().count();
-
-	if (!active_) return;
-
-	StreamPacket spkt = spkt_raw;
-	spkt.localTimestamp = now - int64_t(ttimeoff);
-	spkt.hint_capability = 0;
-	spkt.hint_source_total = 0;
-	spkt.version = 4;
-	if (p) spkt.hint_peerid = p->localID();
-
-	FrameID localFrame(spkt.streamID, spkt.frame_number);
-
-	seen(localFrame, spkt.channel);
-
-	if (paused_) return;
-
-	// Manage recuring requests
-	if (!host_ && last_frame_ != spkt.timestamp) {
-		UNIQUE_LOCK(mutex_, lk);
-		if (last_frame_ != spkt.timestamp) {
-			//int tc = now - last_completion_;			// Milliseconds since last frame completed
-			frame_time_ = spkt.timestamp - last_frame_;	// Milliseconds per frame
-			last_completion_ = now;
-			bytes_received_ = 0;
-			last_frame_ = spkt.timestamp;
-
-			lk.unlock();
-
-			// Are we close to reaching the end of our frames request?
-			if (tally_ <= 5) {
-				// Yes, so send new requests
-				// FIXME: Do this for all frames, or use tally be frame
-				//for (size_t i = 0; i < size(); ++i) {
-					const auto &sel = enabledChannels(localFrame);
-					
-					for (auto c : sel) {
-						_sendRequest(c, localFrame.frameset(), kAllFrames, frames_to_request_, 255);
-					}
-				//}
-				tally_ = frames_to_request_;
-			} else {
-				--tally_;
-			}
-		}
-	}
-
-	bytes_received_ += pkt.data.size();
-	//time_at_last_ = now;
-
-	// If hosting and no data then it is a request for data
-	// Note: a non host can receive empty data, meaning data is available
-	// but that you did not request it
-	if (host_ && pkt.data.size() == 0 && (spkt.flags & ftl::protocol::kFlagRequest)) {
-		_processRequest(p, spkt, pkt);
-	}
-
-	trigger(spkt, pkt);
-	if (pkt.data.size() > 0) _checkRXRate(pkt.data.size(), now-(spkt.timestamp+ttimeoff), spkt.timestamp);
+void Net::_processPacket(ftl::net::Peer *p, int16_t ttimeoff, const StreamPacket &spkt_raw, const Packet &pkt) {
+    int64_t now = time_point_cast<milliseconds>(high_resolution_clock::now()).time_since_epoch().count();
+
+    if (!active_) return;
+
+    StreamPacket spkt = spkt_raw;
+    spkt.localTimestamp = now - int64_t(ttimeoff);
+    spkt.hint_capability = 0;
+    spkt.hint_source_total = 0;
+    spkt.version = 4;
+    if (p) spkt.hint_peerid = p->localID();
+
+    FrameID localFrame(spkt.streamID, spkt.frame_number);
+
+    seen(localFrame, spkt.channel);
+
+    if (paused_) return;
+
+    // Manage recuring requests
+    if (!host_ && last_frame_ != spkt.timestamp) {
+        UNIQUE_LOCK(mutex_, lk);
+        if (last_frame_ != spkt.timestamp) {
+            // int tc = now - last_completion_;          // Milliseconds since last frame completed
+            frame_time_ = spkt.timestamp - last_frame_;  // Milliseconds per frame
+            last_completion_ = now;
+            bytes_received_ = 0;
+            last_frame_ = spkt.timestamp;
+
+            lk.unlock();
+
+            // Are we close to reaching the end of our frames request?
+            if (tally_ <= 5) {
+                // Yes, so send new requests
+                // FIXME: Do this for all frames, or use tally be frame
+                // for (size_t i = 0; i < size(); ++i) {
+                    const auto &sel = enabledChannels(localFrame);
+                    for (auto c : sel) {
+                        _sendRequest(c, localFrame.frameset(), kAllFrames, frames_to_request_, 255);
+                    }
+                //}
+                tally_ = frames_to_request_;
+            } else {
+                --tally_;
+            }
+        }
+    }
+
+    bytes_received_ += pkt.data.size();
+    // time_at_last_ = now;
+
+    // If hosting and no data then it is a request for data
+    // Note: a non host can receive empty data, meaning data is available
+    // but that you did not request it
+    if (host_ && pkt.data.size() == 0 && (spkt.flags & ftl::protocol::kFlagRequest)) {
+        _processRequest(p, &spkt, pkt);
+    }
+
+    trigger(spkt, pkt);
+    if (pkt.data.size() > 0) _checkRXRate(pkt.data.size(), now-(spkt.timestamp+ttimeoff), spkt.timestamp);
 }
 
 void Net::inject(const ftl::protocol::StreamPacket &spkt, const ftl::protocol::Packet &pkt) {
-	_processPacket(nullptr, 0, spkt, pkt);
+    _processPacket(nullptr, 0, spkt, pkt);
 }
 
 bool Net::begin() {
-	if (active_) return true;
-
-	if (net_->isBound(base_uri_)) {
-		error(Error::kURIAlreadyExists, std::string("Stream already exists: ") + uri_);
-		active_ = false;
-		return false;
-	}
-
-	// FIXME: Potential race between above check and new binding
-
-	// Add the RPC handler for the URI
-	net_->bind(base_uri_, [this](ftl::net::Peer &p, short ttimeoff, const StreamPacketMSGPACK &spkt_raw, const PacketMSGPACK &pkt) {
-		_processPacket(&p, ttimeoff, spkt_raw, pkt);
-	});
-
-	if (host_) {
-		DLOG(INFO) << "Hosting stream: " << uri_;
-
-		{
-			// Add to list of available streams
-			UNIQUE_LOCK(stream_mutex, lk);
-			net_streams.push_back(uri_);
-		}
-
-		net_->broadcast("add_stream", uri_);
-		active_ = true;
-		
-	} else {
-		tally_ = frames_to_request_;
-		active_ = true;
-	}
-
-	return true;
+    if (active_) return true;
+
+    if (net_->isBound(base_uri_)) {
+        error(Error::kURIAlreadyExists, std::string("Stream already exists: ") + uri_);
+        active_ = false;
+        return false;
+    }
+
+    // FIXME: Potential race between above check and new binding
+
+    // Add the RPC handler for the URI
+    net_->bind(base_uri_, [this](
+            ftl::net::Peer &p,
+            int16_t ttimeoff,
+            const StreamPacketMSGPACK &spkt_raw,
+            const PacketMSGPACK &pkt) {
+        _processPacket(&p, ttimeoff, spkt_raw, pkt);
+    });
+
+    if (host_) {
+        DLOG(INFO) << "Hosting stream: " << uri_;
+
+        {
+            // Add to list of available streams
+            UNIQUE_LOCK(stream_mutex, lk);
+            net_streams.push_back(uri_);
+        }
+
+        net_->broadcast("add_stream", uri_);
+        active_ = true;
+
+    } else {
+        tally_ = frames_to_request_;
+        active_ = true;
+    }
+
+    return true;
 }
 
 void Net::refresh() {
-	Stream::refresh();
-
-	UNIQUE_LOCK(mutex_, lk);
-
-	for (const auto &i : enabled()) {
-		auto sel = enabledChannels(i);
-		
-		for (auto c : sel) {
-			_sendRequest(c, i.frameset(), kAllFrames, frames_to_request_, 255, true);
-		}
-	}
-	tally_ = frames_to_request_;
+    Stream::refresh();
+
+    UNIQUE_LOCK(mutex_, lk);
+
+    for (const auto &i : enabled()) {
+        auto sel = enabledChannels(i);
+
+        for (auto c : sel) {
+            _sendRequest(c, i.frameset(), kAllFrames, frames_to_request_, 255, true);
+        }
+    }
+    tally_ = frames_to_request_;
 }
 
 void Net::reset() {
-	Stream::reset();
+    Stream::reset();
 }
 
 bool Net::_enable(FrameID id) {
-	if (host_) { return false; }	
-	if (enabled(id)) return true;
-
-	// not hosting, try to find peer now
-	// First find non-proxy version, then check for proxy version if no match
-	auto p = net_->findOne<ftl::UUID>("find_stream", uri_);
-
-	if (p) {
-		peer_ = *p;
-	} else {
-		// use webservice (if connected)
-		auto ws = net_->getWebService();
-		if (ws) {
-			peer_ = ws->id();
-		} else {
-			error(Error::kURIDoesNotExist, std::string("Stream not found: ") + uri_);
-			return false;
-		}
-	}
-	
-	// TODO: check return value
-	net_->send(*peer_, "enable_stream", uri_, id.frameset(), id.source());
-	return true;
+    if (host_) { return false; }
+    if (enabled(id)) return true;
+
+    // not hosting, try to find peer now
+    // First find non-proxy version, then check for proxy version if no match
+    auto p = net_->findOne<ftl::UUID>("find_stream", uri_);
+
+    if (p) {
+        peer_ = *p;
+    } else {
+        // use webservice (if connected)
+        auto ws = net_->getWebService();
+        if (ws) {
+            peer_ = ws->id();
+        } else {
+            error(Error::kURIDoesNotExist, std::string("Stream not found: ") + uri_);
+            return false;
+        }
+    }
+
+    // TODO(Nick): check return value
+    net_->send(*peer_, "enable_stream", uri_, id.frameset(), id.source());
+    return true;
 }
 
 bool Net::enable(FrameID id) {
-	if (host_) { return false; }
-	if (!_enable(id)) return false;
-	if (!Stream::enable(id)) return false;
-	_sendRequest(Channel::kColour, id.frameset(), kAllFrames, kFramesToRequest, 255, true);
+    if (host_) { return false; }
+    if (!_enable(id)) return false;
+    if (!Stream::enable(id)) return false;
+    _sendRequest(Channel::kColour, id.frameset(), kAllFrames, kFramesToRequest, 255, true);
 
-	return true;
+    return true;
 }
 
 bool Net::enable(FrameID id, Channel c) {
-	if (host_) { return false; }
-	if (!_enable(id)) return false;
-	if (!Stream::enable(id, c)) return false;
-	_sendRequest(c, id.frameset(), kAllFrames, kFramesToRequest, 255, true);
-	return true;
+    if (host_) { return false; }
+    if (!_enable(id)) return false;
+    if (!Stream::enable(id, c)) return false;
+    _sendRequest(c, id.frameset(), kAllFrames, kFramesToRequest, 255, true);
+    return true;
 }
 
 bool Net::enable(FrameID id, const ChannelSet &channels) {
-	if (host_) { return false; }
-	if (!_enable(id)) return false;
-	if (!Stream::enable(id, channels)) return false;
-	for (auto c : channels) {
-		_sendRequest(c, id.frameset(), kAllFrames, kFramesToRequest, 255, true);
-	}
-	return true;
+    if (host_) { return false; }
+    if (!_enable(id)) return false;
+    if (!Stream::enable(id, channels)) return false;
+    for (auto c : channels) {
+        _sendRequest(c, id.frameset(), kAllFrames, kFramesToRequest, 255, true);
+    }
+    return true;
 }
 
 bool Net::_sendRequest(Channel c, uint8_t frameset, uint8_t frames, uint8_t count, uint8_t bitrate, bool doreset) {
-	if (!active_ || host_) return false;
-
-	PacketMSGPACK pkt = {
-		Codec::kAny,			// TODO: Allow specific codec requests
-		0,
-		count,
-		bitrate_,
-		0
-	};
-
-	uint8_t sflags = ftl::protocol::kFlagRequest;
-	if (doreset) sflags |= ftl::protocol::kFlagReset;
-
-	StreamPacketMSGPACK spkt = {
-		5,
-		ftl::time::get_time(),
-		frameset,
-		frames,
-		c,
-		sflags,
-		0,
-		0,
-		0
-	};
-
-	net_->send(*peer_, base_uri_, (short)0, spkt, pkt);
-	hasPosted(spkt, pkt);
-	return true;
+    if (!active_ || host_) return false;
+
+    PacketMSGPACK pkt = {
+        Codec::kAny,       // TODO(Nick): Allow specific codec requests
+        0,
+        count,
+        bitrate_,
+        0
+    };
+
+    uint8_t sflags = ftl::protocol::kFlagRequest;
+    if (doreset) sflags |= ftl::protocol::kFlagReset;
+
+    StreamPacketMSGPACK spkt = {
+        5,
+        ftl::time::get_time(),
+        frameset,
+        frames,
+        c,
+        sflags,
+        0,
+        0,
+        0
+    };
+
+    net_->send(*peer_, base_uri_, (int16_t)0, spkt, pkt);
+    hasPosted(spkt, pkt);
+    return true;
 }
 
 void Net::_cleanUp() {
-	UNIQUE_LOCK(mutex_,lk);
-	for (auto i=clients_.begin(); i!=clients_.end(); ++i) {
-		auto &client = *i;
-		if (client.txcount >= client.txmax) {
-			if (client.peerid == time_peer_) {
-				time_peer_ = ftl::UUID(0);
-			}
-			DLOG(INFO) << "Remove peer: " << client.peerid.to_string();
-			i = clients_.erase(i);
-		}
-	}
+    UNIQUE_LOCK(mutex_, lk);
+    for (auto i = clients_.begin(); i != clients_.end(); ++i) {
+        auto &client = *i;
+        if (client.txcount >= client.txmax) {
+            if (client.peerid == time_peer_) {
+                time_peer_ = ftl::UUID(0);
+            }
+            DLOG(INFO) << "Remove peer: " << client.peerid.to_string();
+            i = clients_.erase(i);
+        }
+    }
 }
 
 /* Packets for specific framesets, frames and channels are requested in
  * batches (max 255 unique frames by timestamp). Requests are in the form
  * of packets that match the request except the data component is empty.
  */
-bool Net::_processRequest(ftl::net::Peer *p, StreamPacket &spkt, const Packet &pkt) {
-	bool found = false;
-    DLOG(INFO) << "processing request: " << int(spkt.streamID) << ", " << int(spkt.channel);
-
-	if (p) {
-		SHARED_LOCK(mutex_,lk);
-		// Does the client already exist
-		for (auto &c : clients_) {
-			if (c.peerid == p->id()) {
-				// Yes, so reset internal request counters
-				c.txcount = 0;
-				c.txmax = static_cast<int>(pkt.frame_count);
-				if (int(spkt.channel) < 32) c.channels |= 1 << int(spkt.channel);
-				found = true;
-				// break;
-			}
-		}
-	}
-
-	// No existing client, so add a new one.
-	if (p && !found) {
-		{
-			UNIQUE_LOCK(mutex_,lk);
-
-			auto &client = clients_.emplace_back();
-			client.peerid = p->id();
-			client.quality = 255;  // TODO: Use quality given in packet
-			client.txcount = 0;
-			client.txmax = static_cast<int>(pkt.frame_count);
-			if (int(spkt.channel) < 32) client.channels |= 1 << int(spkt.channel);
-		}
-
-		spkt.hint_capability |= ftl::protocol::kStreamCap_NewConnection;
-
-		try {
-			connect_cb_.trigger(p);
-		} catch (const ftl::exception &e) {
-			LOG(ERROR) << "Exception in stream connect callback: " << e.what();
-		}
-	}
-
-	ftl::protocol::Request req;
-	req.bitrate = pkt.bitrate;
-	req.channel = spkt.channel;
-	req.id = FrameID(spkt.streamID, spkt.frame_number);
-	req.count = pkt.frame_count;
-	req.codec = pkt.codec;
-	request(req);
-
-	return false;
+bool Net::_processRequest(ftl::net::Peer *p, StreamPacket *spkt, const Packet &pkt) {
+    bool found = false;
+    DLOG(INFO) << "processing request: " << int(spkt->streamID) << ", " << int(spkt->channel);
+
+    if (p) {
+        SHARED_LOCK(mutex_, lk);
+        // Does the client already exist
+        for (auto &c : clients_) {
+            if (c.peerid == p->id()) {
+                // Yes, so reset internal request counters
+                c.txcount = 0;
+                c.txmax = static_cast<int>(pkt.frame_count);
+                if (static_cast<int>(spkt->channel) < 32) {
+                    c.channels |= 1 << static_cast<int>(spkt->channel);
+                }
+                found = true;
+                // break;
+            }
+        }
+    }
+
+    // No existing client, so add a new one.
+    if (p && !found) {
+        {
+            UNIQUE_LOCK(mutex_, lk);
+
+            auto &client = clients_.emplace_back();
+            client.peerid = p->id();
+            client.quality = 255;  // TODO(Nick): Use quality given in packet
+            client.txcount = 0;
+            client.txmax = static_cast<int>(pkt.frame_count);
+            if (static_cast<int>(spkt->channel) < 32) {
+                client.channels |= 1 << static_cast<int>(spkt->channel);
+            }
+        }
+
+        spkt->hint_capability |= ftl::protocol::kStreamCap_NewConnection;
+
+        try {
+            connect_cb_.trigger(p);
+        } catch (const ftl::exception &e) {
+            LOG(ERROR) << "Exception in stream connect callback: " << e.what();
+        }
+    }
+
+    ftl::protocol::Request req;
+    req.bitrate = pkt.bitrate;
+    req.channel = spkt->channel;
+    req.id = FrameID(spkt->streamID, spkt->frame_number);
+    req.count = pkt.frame_count;
+    req.codec = pkt.codec;
+    request(req);
+
+    return false;
 }
 
 void Net::_checkRXRate(size_t rx_size, int64_t rx_latency, int64_t ts) {
-	req_bitrate__ += rx_size * 8;
-	rx_sample_count__ += 1;
+    req_bitrate__ += rx_size * 8;
+    rx_sample_count__ += 1;
 }
 
 void Net::_checkTXRate(size_t tx_size, int64_t tx_latency, int64_t ts) {
-	tx_bitrate__ += tx_size * 8;
-	tx_sample_count__ += 1;
+    tx_bitrate__ += tx_size * 8;
+    tx_sample_count__ += 1;
 }
 
 NetStats Net::getStatistics() {
-	int64_t ts = ftl::time::get_time();
-	UNIQUE_LOCK(msg_mtx__,lk);
-	const float r = (float(req_bitrate__) / float(ts - last_msg__) * 1000.0f / 1048576.0f);
-	const float t = (float(tx_bitrate__) / float(ts - last_msg__) * 1000.0f / 1048576.0f);
-	last_msg__ = ts;
-	req_bitrate__ = 0;
-	tx_bitrate__ = 0;
-	rx_sample_count__ = 0;
-	tx_sample_count__ = 0;
-	return {r, t};
+    int64_t ts = ftl::time::get_time();
+    UNIQUE_LOCK(msg_mtx__, lk);
+    const float r = (static_cast<float>(req_bitrate__) / static_cast<float>(ts - last_msg__) * 1000.0f / 1048576.0f);
+    const float t = (static_cast<float>(tx_bitrate__) / static_cast<float>(ts - last_msg__) * 1000.0f / 1048576.0f);
+    last_msg__ = ts;
+    req_bitrate__ = 0;
+    tx_bitrate__ = 0;
+    rx_sample_count__ = 0;
+    tx_sample_count__ = 0;
+    return {r, t};
 }
 
 bool Net::end() {
-	if (!active_) return false;
+    if (!active_) return false;
 
-	{
-		UNIQUE_LOCK(stream_mutex, lk);
-		auto i = std::find(net_streams.begin(), net_streams.end(), uri_);
-		if (i != net_streams.end()) net_streams.erase(i);
-	}
+    {
+        UNIQUE_LOCK(stream_mutex, lk);
+        auto i = std::find(net_streams.begin(), net_streams.end(), uri_);
+        if (i != net_streams.end()) net_streams.erase(i);
+    }
 
-	active_ = false;
-	net_->unbind(base_uri_);
-	return true;
+    active_ = false;
+    net_->unbind(base_uri_);
+    return true;
 }
 
 bool Net::active() {
-	return active_;
+    return active_;
 }
 
 void Net::setProperty(ftl::protocol::StreamProperty opt, std::any value) {
-	switch (opt) {
-	case StreamProperty::kBitrate		:
-	case StreamProperty::kMaxBitrate	:	bitrate_ = std::any_cast<int>(value); break;
-	case StreamProperty::kPaused		:	paused_ = std::any_cast<bool>(value); break;
-	case StreamProperty::kName			:	name_ = std::any_cast<std::string>(value); break;
-	case StreamProperty::kObservers		:
-	case StreamProperty::kBytesSent		:
-	case StreamProperty::kBytesReceived	:
-	case StreamProperty::kLatency		:
-	case StreamProperty::kFrameRate		:
-	case StreamProperty::kURI			:	throw FTL_Error("Readonly property");
-	default								:	throw FTL_Error("Unsupported property");
-	}
+    switch (opt) {
+    case StreamProperty::kBitrate       :
+    case StreamProperty::kMaxBitrate    :  bitrate_ = std::any_cast<int>(value); break;
+    case StreamProperty::kPaused        :  paused_ = std::any_cast<bool>(value); break;
+    case StreamProperty::kName          :  name_ = std::any_cast<std::string>(value); break;
+    case StreamProperty::kObservers     :
+    case StreamProperty::kBytesSent     :
+    case StreamProperty::kBytesReceived :
+    case StreamProperty::kLatency       :
+    case StreamProperty::kFrameRate     :
+    case StreamProperty::kURI           :  throw FTL_Error("Readonly property");
+    default                             :  throw FTL_Error("Unsupported property");
+    }
 }
 
 std::any Net::getProperty(ftl::protocol::StreamProperty opt) {
-	switch (opt) {
-	case StreamProperty::kBitrate		:
-	case StreamProperty::kMaxBitrate	:	return bitrate_;
-	case StreamProperty::kObservers		:	return clients_.size();
-	case StreamProperty::kURI			:	return base_uri_;
-	case StreamProperty::kPaused		:	return paused_;
-	case StreamProperty::kBytesSent		:	return 0;
-	case StreamProperty::kBytesReceived	:	return int64_t(bytes_received_);
-	case StreamProperty::kFrameRate		:	return (frame_time_ > 0) ? 1000 / frame_time_ : 0;
-	case StreamProperty::kLatency		:	return 0;
-	case StreamProperty::kName			:	return name_;
-	default								:	throw FTL_Error("Unsupported property");
-	}
+    switch (opt) {
+    case StreamProperty::kBitrate       :
+    case StreamProperty::kMaxBitrate    :  return bitrate_;
+    case StreamProperty::kObservers     :  return clients_.size();
+    case StreamProperty::kURI           :  return base_uri_;
+    case StreamProperty::kPaused        :  return paused_;
+    case StreamProperty::kBytesSent     :  return 0;
+    case StreamProperty::kBytesReceived :  return int64_t(bytes_received_);
+    case StreamProperty::kFrameRate     :  return (frame_time_ > 0) ? 1000 / frame_time_ : 0;
+    case StreamProperty::kLatency       :  return 0;
+    case StreamProperty::kName          :  return name_;
+    default                             :  throw FTL_Error("Unsupported property");
+    }
 }
 
 bool Net::supportsProperty(ftl::protocol::StreamProperty opt) {
-	switch (opt) {
-	case StreamProperty::kBitrate		:
-	case StreamProperty::kMaxBitrate	:
-	case StreamProperty::kObservers		:
-	case StreamProperty::kPaused		:
-	case StreamProperty::kBytesSent		:
-	case StreamProperty::kBytesReceived	:
-	case StreamProperty::kLatency		:
-	case StreamProperty::kFrameRate		:
-	case StreamProperty::kName			:
-	case StreamProperty::kURI			:	return true;
-	default								:	return false;
-	}
+    switch (opt) {
+    case StreamProperty::kBitrate       :
+    case StreamProperty::kMaxBitrate    :
+    case StreamProperty::kObservers     :
+    case StreamProperty::kPaused        :
+    case StreamProperty::kBytesSent     :
+    case StreamProperty::kBytesReceived :
+    case StreamProperty::kLatency       :
+    case StreamProperty::kFrameRate     :
+    case StreamProperty::kName          :
+    case StreamProperty::kURI           :  return true;
+    default                             :  return false;
+    }
 }
 
 ftl::protocol::StreamType Net::type() const {
-	return ftl::protocol::StreamType::kLive;
+    return ftl::protocol::StreamType::kLive;
 }
diff --git a/src/streams/netstream.hpp b/src/streams/netstream.hpp
index d311f9d332962dc47d3c9fa3b7e050709fb6398f..c861077a68821ccdb3f52ed71e4116573b570676 100644
--- a/src/streams/netstream.hpp
+++ b/src/streams/netstream.hpp
@@ -1,22 +1,29 @@
+/**
+ * @file netstream.hpp
+ * @copyright Copyright (c) 2022 University of Turku, MIT License
+ * @author Nicolas Pope
+ */
+
 #pragma once
 
+#include <string>
+#include <list>
 #include "../universe.hpp"
 #include <ftl/threads.hpp>
 #include <ftl/protocol/packet.hpp>
 #include <ftl/protocol/streams.hpp>
 #include <ftl/handle.hpp>
-#include <string>
 
 namespace ftl {
 namespace protocol {
 
 namespace detail {
 struct StreamClient {
-	ftl::UUID peerid;
-	std::atomic<int> txcount;			// Frames sent since last request
-	int txmax;							// Frames to send in request
-	std::atomic<uint32_t> channels;		// A channel mask, those that have been requested
-	uint8_t quality;
+    ftl::UUID peerid;
+    std::atomic<int> txcount;           // Frames sent since last request
+    int txmax;                          // Frames to send in request
+    std::atomic<uint32_t> channels;     // A channel mask, those that have been requested
+    uint8_t quality;
 };
 }
 
@@ -26,8 +33,8 @@ struct StreamClient {
 static const int kMaxFrames = 100;
 
 struct NetStats {
-	float rxRate;
-	float txRate;
+    float rxRate;
+    float txRate;
 };
 
 /**
@@ -36,97 +43,103 @@ struct NetStats {
  * Each packet post is forwarded to each connected client that is still active.
  */
 class Net : public Stream {
-	public:
-	Net(const std::string &uri, ftl::net::Universe *net, bool host=false);
-	virtual ~Net();
-
-	bool post(const ftl::protocol::StreamPacket &, const ftl::protocol::Packet &) override;
-
-	bool begin() override;
-	bool end() override;
-	bool active() override;
-
-	bool enable(FrameID id) override;
-	bool enable(FrameID id, ftl::protocol::Channel c) override;
-	bool enable(FrameID id, const ftl::protocol::ChannelSet &channels) override;
-
-	void reset() override;
-	void refresh() override;
-
-	void setProperty(ftl::protocol::StreamProperty opt, std::any value) override;
-	std::any getProperty(ftl::protocol::StreamProperty opt) override;
-	bool supportsProperty(ftl::protocol::StreamProperty opt) override;
-	StreamType type() const override;
-
-	inline const ftl::UUID &getPeer() const {
-		if (host_) { throw FTL_Error("Net::getPeer() not possible, hosting stream"); }
-		if (!peer_){ throw FTL_Error("steram::Net has no valid Peer. Not found earlier?"); }
-		return *peer_;
-	}
-
-	inline ftl::Handle onClientConnect(const std::function<bool(ftl::net::Peer*)> &cb) { return connect_cb_.on(cb); }
-
-	/**
-	 * Return the average bitrate of all streams since the last call to this
-	 * function. Units are Mbps.
-	 */
-	static NetStats getStatistics();
-
-	static void installRPC(ftl::net::Universe *net);
-
-	static constexpr int kFramesToRequest = 30;
-
-	// Unit test support
-	virtual void hasPosted(const ftl::protocol::StreamPacket &, const ftl::protocol::Packet &) {}
-	void inject(const ftl::protocol::StreamPacket &, const ftl::protocol::Packet &);
-
-private:
-	SHARED_MUTEX mutex_;
-	bool active_ = false;
-	ftl::net::Universe *net_;
-	int64_t clock_adjust_ = 0;
-	ftl::UUID time_peer_;
-	std::optional<ftl::UUID> peer_;
-	int64_t last_frame_ = 0;
-	int64_t last_ping_ = 0;
-	int64_t frame_time_ = 0;
-	std::string uri_;
-	std::string base_uri_;
-	const bool host_;
-	int tally_ = 0;
-	std::array<std::atomic<int>,32> reqtally_ = {0};
-	ftl::protocol::ChannelSet last_selected_;
-	uint8_t bitrate_ = 200;
-	std::atomic_int64_t bytes_received_ = 0;
-	int64_t last_completion_ = 0;
-	int64_t time_at_last_ = 0;
-	float required_bps_ = 0.0f;
-	float actual_bps_ = 0.0f;
-	bool paused_ = false;
-	int frames_to_request_ = kFramesToRequest;
-	std::string name_;
-
-	ftl::Handler<ftl::net::Peer*> connect_cb_;
-
-	uint32_t local_fsid_ = 0;
-
-	static std::atomic_size_t req_bitrate__;
-	static std::atomic_size_t tx_bitrate__;
-	static std::atomic_size_t rx_sample_count__;
-	static std::atomic_size_t tx_sample_count__;
-	static int64_t last_msg__;
-	static MUTEX msg_mtx__;
-
-	std::list<detail::StreamClient> clients_;
-
-	bool _enable(FrameID id);
-	bool _processRequest(ftl::net::Peer *p, ftl::protocol::StreamPacket &spkt, const ftl::protocol::Packet &pkt);
-	void _checkRXRate(size_t rx_size, int64_t rx_latency, int64_t ts);
-	void _checkTXRate(size_t tx_size, int64_t tx_latency, int64_t ts);
-	bool _sendRequest(ftl::protocol::Channel c, uint8_t frameset, uint8_t frames, uint8_t count, uint8_t bitrate, bool doreset=false);
-	void _cleanUp();
-	void _processPacket(ftl::net::Peer *p, short ttimeoff, const StreamPacket &spkt_raw, const Packet &pkt);
+ public:
+    Net(const std::string &uri, ftl::net::Universe *net, bool host = false);
+    virtual ~Net();
+
+    bool post(const ftl::protocol::StreamPacket &, const ftl::protocol::Packet &) override;
+
+    bool begin() override;
+    bool end() override;
+    bool active() override;
+
+    bool enable(FrameID id) override;
+    bool enable(FrameID id, ftl::protocol::Channel c) override;
+    bool enable(FrameID id, const ftl::protocol::ChannelSet &channels) override;
+
+    void reset() override;
+    void refresh() override;
+
+    void setProperty(ftl::protocol::StreamProperty opt, std::any value) override;
+    std::any getProperty(ftl::protocol::StreamProperty opt) override;
+    bool supportsProperty(ftl::protocol::StreamProperty opt) override;
+    StreamType type() const override;
+
+    inline const ftl::UUID &getPeer() const {
+        if (host_) { throw FTL_Error("Net::getPeer() not possible, hosting stream"); }
+        if (!peer_) { throw FTL_Error("steram::Net has no valid Peer. Not found earlier?"); }
+        return *peer_;
+    }
+
+    inline ftl::Handle onClientConnect(const std::function<bool(ftl::net::Peer*)> &cb) { return connect_cb_.on(cb); }
+
+    /**
+     * Return the average bitrate of all streams since the last call to this
+     * function. Units are Mbps.
+     */
+    static NetStats getStatistics();
+
+    static void installRPC(ftl::net::Universe *net);
+
+    static constexpr int kFramesToRequest = 30;
+
+    // Unit test support
+    virtual void hasPosted(const ftl::protocol::StreamPacket &, const ftl::protocol::Packet &) {}
+    void inject(const ftl::protocol::StreamPacket &, const ftl::protocol::Packet &);
+
+ private:
+    SHARED_MUTEX mutex_;
+    bool active_ = false;
+    ftl::net::Universe *net_;
+    int64_t clock_adjust_ = 0;
+    ftl::UUID time_peer_;
+    std::optional<ftl::UUID> peer_;
+    int64_t last_frame_ = 0;
+    int64_t last_ping_ = 0;
+    int64_t frame_time_ = 0;
+    std::string uri_;
+    std::string base_uri_;
+    const bool host_;
+    int tally_ = 0;
+    std::array<std::atomic<int>, 32> reqtally_ = {0};
+    ftl::protocol::ChannelSet last_selected_;
+    uint8_t bitrate_ = 200;
+    std::atomic_int64_t bytes_received_ = 0;
+    int64_t last_completion_ = 0;
+    int64_t time_at_last_ = 0;
+    float required_bps_ = 0.0f;
+    float actual_bps_ = 0.0f;
+    bool paused_ = false;
+    int frames_to_request_ = kFramesToRequest;
+    std::string name_;
+
+    ftl::Handler<ftl::net::Peer*> connect_cb_;
+
+    uint32_t local_fsid_ = 0;
+
+    static std::atomic_size_t req_bitrate__;
+    static std::atomic_size_t tx_bitrate__;
+    static std::atomic_size_t rx_sample_count__;
+    static std::atomic_size_t tx_sample_count__;
+    static int64_t last_msg__;
+    static MUTEX msg_mtx__;
+
+    std::list<detail::StreamClient> clients_;
+
+    bool _enable(FrameID id);
+    bool _processRequest(ftl::net::Peer *p, ftl::protocol::StreamPacket *spkt, const ftl::protocol::Packet &pkt);
+    void _checkRXRate(size_t rx_size, int64_t rx_latency, int64_t ts);
+    void _checkTXRate(size_t tx_size, int64_t tx_latency, int64_t ts);
+    bool _sendRequest(
+        ftl::protocol::Channel c,
+        uint8_t frameset,
+        uint8_t frames,
+        uint8_t count,
+        uint8_t bitrate,
+        bool doreset = false);
+    void _cleanUp();
+    void _processPacket(ftl::net::Peer *p, int16_t ttimeoff, const StreamPacket &spkt_raw, const Packet &pkt);
 };
 
-}
-}
+}  // namespace protocol
+}  // namespace ftl
diff --git a/src/streams/packetMsgpack.hpp b/src/streams/packetMsgpack.hpp
index 79f577cb8c56cc5c588d1393a054f27348331a2c..f8aca04a05a7406c4c610b62868397a537d93ef1 100644
--- a/src/streams/packetMsgpack.hpp
+++ b/src/streams/packetMsgpack.hpp
@@ -1,3 +1,9 @@
+/**
+ * @file packetMsgpack.hpp
+ * @copyright Copyright (c) 2022 University of Turku, MIT License
+ * @author Nicolas Pope
+ */
+
 #pragma once
 
 #include <ftl/protocol/packet.hpp>
@@ -20,5 +26,5 @@ struct PacketMSGPACK : ftl::protocol::Packet {
 static_assert(sizeof(StreamPacketMSGPACK) == sizeof(StreamPacket));
 static_assert(sizeof(PacketMSGPACK) == sizeof(Packet));
 
-}
-}
+}  // namespace protocol
+}  // namespace ftl
diff --git a/src/streams/streams.cpp b/src/streams/streams.cpp
index bf12a13c415526135d9a886d815d7ee1687ff3b2..bf5ba8c14a2f828067b152fab98526420bb8ef82 100644
--- a/src/streams/streams.cpp
+++ b/src/streams/streams.cpp
@@ -1,3 +1,9 @@
+/**
+ * @file streams.cpp
+ * @copyright Copyright (c) 2022 University of Turku, MIT License
+ * @author Nicolas Pope
+ */
+
 #include <ftl/protocol/streams.hpp>
 
 using ftl::protocol::Stream;
@@ -6,143 +12,141 @@ using ftl::protocol::ChannelSet;
 using ftl::protocol::FrameID;
 
 std::string Stream::name() const {
-	return "Unknown";
+    return "Unknown";
 }
 
 bool Stream::available(FrameID id) const {
-	SHARED_LOCK(mtx_, lk);
-	return state_.count(id) > 0;
+    SHARED_LOCK(mtx_, lk);
+    return state_.count(id) > 0;
 }
 
 bool Stream::available(FrameID id, Channel channel) const {
-	SHARED_LOCK(mtx_, lk);
-	auto it = state_.find(id);
-	if (it != state_.end()) {
-		return it->second.available.count(channel) > 0;
-	}
-	return false;
+    SHARED_LOCK(mtx_, lk);
+    auto it = state_.find(id);
+    if (it != state_.end()) {
+        return it->second.available.count(channel) > 0;
+    }
+    return false;
 }
 
 bool Stream::available(FrameID id, ChannelSet channels) const {
-	SHARED_LOCK(mtx_, lk);
-	auto it = state_.find(id);
-	if (it != state_.end()) {
-		const auto &set = it->second.available;
-		for (auto channel : channels) {
-			if (set.count(channel) == 0) return false;
-		}
-		return true;
-	}
-	return false;
+    SHARED_LOCK(mtx_, lk);
+    auto it = state_.find(id);
+    if (it != state_.end()) {
+        const auto &set = it->second.available;
+        for (auto channel : channels) {
+            if (set.count(channel) == 0) return false;
+        }
+        return true;
+    }
+    return false;
 }
 
 ftl::protocol::ChannelSet Stream::channels(FrameID id) const {
-	SHARED_LOCK(mtx_, lk);
-	auto it = state_.find(id);
-	if (it != state_.end()) {
-		return it->second.available;
-	}
-	return {};
+    SHARED_LOCK(mtx_, lk);
+    auto it = state_.find(id);
+    if (it != state_.end()) {
+        return it->second.available;
+    }
+    return {};
 }
 
 std::unordered_set<FrameID> Stream::frames() const {
-	SHARED_LOCK(mtx_, lk);
-	std::unordered_set<FrameID> result;
-	for (const auto &s : state_) {
-		result.insert(FrameID(s.first));
-	}
-	return result;
+    SHARED_LOCK(mtx_, lk);
+    std::unordered_set<FrameID> result;
+    for (const auto &s : state_) {
+        result.insert(FrameID(s.first));
+    }
+    return result;
 }
 
 std::unordered_set<FrameID> Stream::enabled() const {
-	SHARED_LOCK(mtx_, lk);
-	std::unordered_set<FrameID> result;
-	for (const auto &s : state_) {
-		if (s.second.enabled) {
-			result.emplace(s.first);
-		}
-	}
-	return result;
+    SHARED_LOCK(mtx_, lk);
+    std::unordered_set<FrameID> result;
+    for (const auto &s : state_) {
+        if (s.second.enabled) {
+            result.emplace(s.first);
+        }
+    }
+    return result;
 }
 
 bool Stream::enabled(FrameID id) const {
-	SHARED_LOCK(mtx_, lk);
-	auto it = state_.find(id);
-	if (it != state_.end()) {
-		return it->second.enabled;
-	}
-	return false;
+    SHARED_LOCK(mtx_, lk);
+    auto it = state_.find(id);
+    if (it != state_.end()) {
+        return it->second.enabled;
+    }
+    return false;
 }
 
 bool Stream::enabled(FrameID id, ftl::protocol::Channel channel) const {
-	SHARED_LOCK(mtx_, lk);
-	auto it = state_.find(id);
-	if (it != state_.end()) {
-		return it->second.selected.count(channel) > 0;
-	}
-	return false;
+    SHARED_LOCK(mtx_, lk);
+    auto it = state_.find(id);
+    if (it != state_.end()) {
+        return it->second.selected.count(channel) > 0;
+    }
+    return false;
 }
 
 ftl::protocol::ChannelSet Stream::enabledChannels(FrameID id) const {
-	SHARED_LOCK(mtx_, lk);
-	auto it = state_.find(id);
-	if (it != state_.end()) {
-		return it->second.selected;
-	}
-	return {};
+    SHARED_LOCK(mtx_, lk);
+    auto it = state_.find(id);
+    if (it != state_.end()) {
+        return it->second.selected;
+    }
+    return {};
 }
 
 bool Stream::enable(FrameID id) {
-	UNIQUE_LOCK(mtx_, lk);
-	auto &p = state_[id];
-	p.enabled = true;
-	return true;
+    UNIQUE_LOCK(mtx_, lk);
+    auto &p = state_[id];
+    p.enabled = true;
+    return true;
 }
 
 bool Stream::enable(FrameID id, ftl::protocol::Channel channel) {
-	UNIQUE_LOCK(mtx_, lk);
-	auto &p = state_[id];
-	p.enabled = true;
-	p.selected.insert(channel);
-	return true;
+    UNIQUE_LOCK(mtx_, lk);
+    auto &p = state_[id];
+    p.enabled = true;
+    p.selected.insert(channel);
+    return true;
 }
 
 bool Stream::enable(FrameID id, const ftl::protocol::ChannelSet &channels) {
-	UNIQUE_LOCK(mtx_, lk);
-	auto &p = state_[id];
-	p.enabled = true;
-	p.selected.insert(channels.begin(), channels.end());
-	return true;
+    UNIQUE_LOCK(mtx_, lk);
+    auto &p = state_[id];
+    p.enabled = true;
+    p.selected.insert(channels.begin(), channels.end());
+    return true;
 }
 
 void Stream::reset() {
-	UNIQUE_LOCK(mtx_, lk);
-	state_.clear();
+    UNIQUE_LOCK(mtx_, lk);
+    state_.clear();
 }
 
-void Stream::refresh() {
-
-}
+void Stream::refresh() {}
 
 void Stream::trigger(const ftl::protocol::StreamPacket &spkt, const ftl::protocol::Packet &pkt) {
-	cb_.trigger(spkt, pkt);
+    cb_.trigger(spkt, pkt);
 }
 
 void Stream::seen(FrameID id, ftl::protocol::Channel channel) {
-	if (!available(id, channel)) {
-		{
-			UNIQUE_LOCK(mtx_, lk);
-			auto &p = state_[id];
-			p.available.insert(channel);
-		}
-		avail_cb_.trigger(id, channel);
-	}
+    if (!available(id, channel)) {
+        {
+            UNIQUE_LOCK(mtx_, lk);
+            auto &p = state_[id];
+            p.available.insert(channel);
+        }
+        avail_cb_.trigger(id, channel);
+    }
 }
 
 void Stream::request(const ftl::protocol::Request &req) {
-	request_cb_.trigger(req);
+    request_cb_.trigger(req);
 }
 
 void Stream::error(ftl::protocol::Error err, const std::string &str) {
-	error_cb_.trigger(err, str);
+    error_cb_.trigger(err, str);
 }
diff --git a/src/time.cpp b/src/time.cpp
index 772a7036dedbf01f64d0ed5c7e041fe871abf47c..27f496b45465082cfd4371adb506d041f7b581fa 100644
--- a/src/time.cpp
+++ b/src/time.cpp
@@ -1,24 +1,32 @@
-#include <ftl/time.hpp>
+/**
+ * @file time.cpp
+ * @copyright Copyright (c) 2022 University of Turku, MIT License
+ * @author Nicolas Pope
+ */
+
 #include <chrono>
+#include <ftl/time.hpp>
 
 using std::chrono::time_point_cast;
 using std::chrono::milliseconds;
+using std::chrono::microseconds;
 using std::chrono::high_resolution_clock;
 
 static int64_t clock_adjust = 0;
 
 int64_t ftl::time::get_time() {
-	return time_point_cast<milliseconds>(high_resolution_clock::now()).time_since_epoch().count()+clock_adjust;
+    return time_point_cast<milliseconds>(high_resolution_clock::now()).time_since_epoch().count()+clock_adjust;
 }
 
 int64_t ftl::time::get_time_micro() {
-	return time_point_cast<std::chrono::microseconds>(high_resolution_clock::now()).time_since_epoch().count()+(clock_adjust*1000);
+    return time_point_cast<microseconds>(high_resolution_clock::now()).time_since_epoch().count()+(clock_adjust*1000);
 }
 
 double ftl::time::get_time_seconds() {
-	return time_point_cast<std::chrono::microseconds>(high_resolution_clock::now()).time_since_epoch().count() / 1000000.0 + (static_cast<double>(clock_adjust) / 1000.0);
+    return time_point_cast<microseconds>(high_resolution_clock::now()).time_since_epoch().count() / 1000000.0
+        + (static_cast<double>(clock_adjust) / 1000.0);
 }
 
 void ftl::time::setClockAdjustment(int64_t ms) {
-	clock_adjust += ms;
+    clock_adjust += ms;
 }
diff --git a/src/universe.cpp b/src/universe.cpp
index ba6fc3b856e24d86fa893c2101ddf1fcbf31c1d5..26356e78b99f1e1c40d5b9fb1325e86eb4c4b5ca 100644
--- a/src/universe.cpp
+++ b/src/universe.cpp
@@ -4,10 +4,13 @@
  * @author Nicolas Pope
  */
 
-#include "universe.hpp"
-#include "socketImpl.hpp"
 #include <chrono>
+#include <utility>
 #include <algorithm>
+#include <memory>
+#include <unordered_map>
+#include "universe.hpp"
+#include "socketImpl.hpp"
 
 #define LOGURU_REPLACE_GLOG 1
 #include <ftl/lib/loguru.hpp>
@@ -42,606 +45,596 @@ using ftl::protocol::NodeStatus;
 using ftl::protocol::NodeType;
 using ftl::net::internal::SocketServer;
 using ftl::net::internal::Server_TCP;
+using std::chrono::milliseconds;
 
 namespace ftl {
 namespace net {
 
 std::unique_ptr<SocketServer> create_listener(const ftl::URI &uri) {
-	if (uri.getProtocol() == ftl::URI::scheme_t::SCHEME_TCP) {
-		return std::make_unique<Server_TCP>(uri.getHost(), uri.getPort());
-	}
-	if (uri.getProtocol() == ftl::URI::scheme_t::SCHEME_WS) {
-		throw FTL_Error("WebSocket listener not implemented");
-	}
-	return nullptr;
+    if (uri.getProtocol() == ftl::URI::scheme_t::SCHEME_TCP) {
+        return std::make_unique<Server_TCP>(uri.getHost(), uri.getPort());
+    }
+    if (uri.getProtocol() == ftl::URI::scheme_t::SCHEME_WS) {
+        throw FTL_Error("WebSocket listener not implemented");
+    }
+    return nullptr;
 }
 
 struct NetImplDetail {
-	//fd_set sfderror_;
-	//fd_set sfdread_;
-	std::vector<pollfd> pollfds;
-	std::unordered_map<int,size_t> idMap;
+    std::vector<pollfd> pollfds;
+    std::unordered_map<int, size_t> idMap;
 };
 
-}
-}
+}  // namespace net
+}  // namespace ftl
 
-// TODO: move to ServerSocket and ClientSocket
+// TODO(Seb): move to ServerSocket and ClientSocket
 // Defaults, should be changed in config
-#define TCP_SEND_BUFFER_SIZE	(1024*1024)
-#define TCP_RECEIVE_BUFFER_SIZE	(1024*1024)  // Perhaps try 24K?
-#define WS_SEND_BUFFER_SIZE	(1024*1024)
-#define WS_RECEIVE_BUFFER_SIZE	(62*1024)
+#define TCP_SEND_BUFFER_SIZE    (1024*1024)
+#define TCP_RECEIVE_BUFFER_SIZE (1024*1024)  // Perhaps try 24K?
+#define WS_SEND_BUFFER_SIZE     (1024*1024)
+#define WS_RECEIVE_BUFFER_SIZE  (62*1024)
 
 std::shared_ptr<Universe> Universe::instance_ = nullptr;
 
 Universe::Universe() :
-		active_(true),
-		this_peer(ftl::protocol::id),
-		impl_(new ftl::net::NetImplDetail()),
-		peers_(10),
-		phase_(0),
-		periodic_time_(1.0),
-		reconnect_attempts_(5),
-		thread_(Universe::__start, this) {
-
-	_installBindings();
-
-	// Add an idle timer job to garbage collect peer objects
-	// Note: Important to be a timer job to ensure no other timer jobs are
-	// using the object.
-	// FIXME: Replace use of timer.
-	/*garbage_timer_ = ftl::timer::add(ftl::timer::kTimerIdle10, [this](int64_t ts) {
-		if (garbage_.size() > 0) {
-			UNIQUE_LOCK(net_mutex_,lk);
-			if (ftl::pool.n_idle() == ftl::pool.size()) {
-				if (garbage_.size() > 0) LOG(1) << "Garbage collection";
-				while (garbage_.size() > 0) {
-					delete garbage_.front();
-					garbage_.pop_front();
-				}
-			}
-		}
-		return true;
-	});*/
+        active_(true),
+        this_peer(ftl::protocol::id),
+        impl_(new ftl::net::NetImplDetail()),
+        peers_(10),
+        phase_(0),
+        periodic_time_(1.0),
+        reconnect_attempts_(5),
+        thread_(Universe::__start, this) {
+    _installBindings();
+
+    // Add an idle timer job to garbage collect peer objects
+    // Note: Important to be a timer job to ensure no other timer jobs are
+    // using the object.
+    // FIXME: Replace use of timer.
+    /*garbage_timer_ = ftl::timer::add(ftl::timer::kTimerIdle10, [this](int64_t ts) {
+        if (garbage_.size() > 0) {
+            UNIQUE_LOCK(net_mutex_,lk);
+            if (ftl::pool.n_idle() == ftl::pool.size()) {
+                if (garbage_.size() > 0) LOG(1) << "Garbage collection";
+                while (garbage_.size() > 0) {
+                    delete garbage_.front();
+                    garbage_.pop_front();
+                }
+            }
+        }
+        return true;
+    });*/
 }
 
 Universe::~Universe() {
-	shutdown();
-	CHECK(peer_instances_ == 0);
+    shutdown();
+    CHECK_EQ(peer_instances_, 0);
 }
 
 size_t Universe::getSendBufferSize(ftl::URI::scheme_t s) {
-	// TODO: Allow these to be configured again.
-	switch(s) {
-		case ftl::URI::scheme_t::SCHEME_WS:
-		case ftl::URI::scheme_t::SCHEME_WSS:
-			return WS_SEND_BUFFER_SIZE;
+    // TODO(Nick): Allow these to be configured again.
+    switch (s) {
+        case ftl::URI::scheme_t::SCHEME_WS:
+        case ftl::URI::scheme_t::SCHEME_WSS:
+            return WS_SEND_BUFFER_SIZE;
 
-		default:
-			return TCP_SEND_BUFFER_SIZE;
-	}		
+        default:
+            return TCP_SEND_BUFFER_SIZE;
+    }
 }
 
 size_t Universe::getRecvBufferSize(ftl::URI::scheme_t s) {
-	switch(s) {
-		case ftl::URI::scheme_t::SCHEME_WS:
-		case ftl::URI::scheme_t::SCHEME_WSS:
-			return WS_RECEIVE_BUFFER_SIZE;
-		
-		default:
-			return TCP_RECEIVE_BUFFER_SIZE;
-	}
+    switch (s) {
+        case ftl::URI::scheme_t::SCHEME_WS:
+        case ftl::URI::scheme_t::SCHEME_WSS:
+            return WS_RECEIVE_BUFFER_SIZE;
+        default:
+            return TCP_RECEIVE_BUFFER_SIZE;
+    }
 }
 
 void Universe::start() {
-
-	/*auto l = get<json_t>("listen");
-
-	if (l && (*l).is_array()) {
-		for (auto &ll : *l) {
-			listen(ftl::URI(ll));
-		}
-	} else if (l && (*l).is_string()) {
-		listen(ftl::URI((*l).get<string>()));
-	}
-	
-	auto p = get<json_t>("peers");
-	if (p && (*p).is_array()) {
-		for (auto &pp : *p) {
-			try {
-				connect(pp);
-			} catch (const ftl::exception &ex) {
-				LOG(ERROR) << "Could not connect to: " << std::string(pp);
-			}
-		}
-	}*/
+    /*auto l = get<json_t>("listen");
+
+    if (l && (*l).is_array()) {
+        for (auto &ll : *l) {
+            listen(ftl::URI(ll));
+        }
+    } else if (l && (*l).is_string()) {
+        listen(ftl::URI((*l).get<string>()));
+    }
+    
+    auto p = get<json_t>("peers");
+    if (p && (*p).is_array()) {
+        for (auto &pp : *p) {
+            try {
+                connect(pp);
+            } catch (const ftl::exception &ex) {
+                LOG(ERROR) << "Could not connect to: " << std::string(pp);
+            }
+        }
+    }*/
 }
 
 void Universe::shutdown() {
-	if (!active_) return;
-	DLOG(1) << "Cleanup Network ...";
+    if (!active_) return;
+    DLOG(1) << "Cleanup Network ...";
 
-	{
-		SHARED_LOCK(net_mutex_, lk);
+    {
+        SHARED_LOCK(net_mutex_, lk);
 
-		for (auto &l : listeners_) {
-			l->close();
-		}
+        for (auto &l : listeners_) {
+            l->close();
+        }
 
-		for (auto &s : peers_) {
-			if (s) s->rawClose();
-		}
-	}
+        for (auto &s : peers_) {
+            if (s) s->rawClose();
+        }
+    }
 
-	active_ = false;
-	thread_.join();
+    active_ = false;
+    thread_.join();
 
-	// FIXME: This shouldn't be needed
-	if (peer_instances_ > 0 && ftl::pool.size() > 0) {
-		DLOG(WARNING) << "Waiting on peer destruction... " << peer_instances_;
-		std::this_thread::sleep_for(std::chrono::milliseconds(2));
-		if (peer_instances_ > 0) LOG(FATAL) << "Peers not destroyed";
-	}
+    // FIXME: This shouldn't be needed
+    if (peer_instances_ > 0 && ftl::pool.size() > 0) {
+        DLOG(WARNING) << "Waiting on peer destruction... " << peer_instances_;
+        std::this_thread::sleep_for(std::chrono::milliseconds(2));
+        if (peer_instances_ > 0) LOG(FATAL) << "Peers not destroyed";
+    }
 }
 
 bool Universe::listen(const ftl::URI &addr) {
-	try {
-		auto l = create_listener(addr);
-		l->bind();
-
-		{
-			UNIQUE_LOCK(net_mutex_,lk);
-			DLOG(1) << "listening on " << l->uri().to_string();
-			listeners_.push_back(std::move(l));
-		}
-		socket_cv_.notify_one();
-		return true;
-
-	} catch (const std::exception &ex) {
-		DLOG(INFO) << "Can't listen " << addr.to_string() << ", " << ex.what();
-		_notifyError(nullptr, ftl::protocol::Error::kListen, ex.what());
-		return false;
-	}
+    try {
+        auto l = create_listener(addr);
+        l->bind();
+
+        {
+            UNIQUE_LOCK(net_mutex_, lk);
+            DLOG(1) << "listening on " << l->uri().to_string();
+            listeners_.push_back(std::move(l));
+        }
+        socket_cv_.notify_one();
+        return true;
+    } catch (const std::exception &ex) {
+        DLOG(INFO) << "Can't listen " << addr.to_string() << ", " << ex.what();
+        _notifyError(nullptr, ftl::protocol::Error::kListen, ex.what());
+        return false;
+    }
 }
 
 std::vector<ftl::URI> Universe::getListeningURIs() {
-	SHARED_LOCK(net_mutex_, lk);
-	std::vector<ftl::URI> uris(listeners_.size());
-	std::transform(listeners_.begin(), listeners_.end(), uris.begin(), [](const auto &l){ return l->uri(); });
-	return uris;
+    SHARED_LOCK(net_mutex_, lk);
+    std::vector<ftl::URI> uris(listeners_.size());
+    std::transform(listeners_.begin(), listeners_.end(), uris.begin(), [](const auto &l){ return l->uri(); });
+    return uris;
 }
 
 bool Universe::isConnected(const ftl::URI &uri) {
-	SHARED_LOCK(net_mutex_,lk);
-	return (peer_by_uri_.find(uri.getBaseURI()) != peer_by_uri_.end());
+    SHARED_LOCK(net_mutex_, lk);
+    return (peer_by_uri_.find(uri.getBaseURI()) != peer_by_uri_.end());
 }
 
 bool Universe::isConnected(const std::string &s) {
-	ftl::URI uri(s);
-	return isConnected(uri);
+    ftl::URI uri(s);
+    return isConnected(uri);
 }
 
 void Universe::_insertPeer(const PeerPtr &ptr) {
-	UNIQUE_LOCK(net_mutex_,lk);
-	for (size_t i=0; i<peers_.size(); ++i) {
-		if (!peers_[i]) {
-			++connection_count_;
-			peers_[i] = ptr;
-			peer_by_uri_[ptr->getURIObject().getBaseURI()] = i;
-			peer_ids_[ptr->id()] = i;
-			ptr->local_id_ = i;
-
-			lk.unlock();
-			socket_cv_.notify_one();
-			return;
-		}
-	}
-	throw FTL_Error("Too many connections");
+    UNIQUE_LOCK(net_mutex_, lk);
+    for (size_t i = 0; i < peers_.size(); ++i) {
+        if (!peers_[i]) {
+            ++connection_count_;
+            peers_[i] = ptr;
+            peer_by_uri_[ptr->getURIObject().getBaseURI()] = i;
+            peer_ids_[ptr->id()] = i;
+            ptr->local_id_ = i;
+
+            lk.unlock();
+            socket_cv_.notify_one();
+            return;
+        }
+    }
+    throw FTL_Error("Too many connections");
 }
 
 PeerPtr Universe::connect(const ftl::URI &u) {
+    // Check if already connected or if self (when could this happen?)
+    {
+        SHARED_LOCK(net_mutex_, lk);
+        if (peer_by_uri_.find(u.getBaseURI()) != peer_by_uri_.end()) {
+            return peers_[peer_by_uri_.at(u.getBaseURI())];
+        }
+
+        if (u.getHost() == "localhost" || u.getHost() == "127.0.0.1") {
+            if (std::any_of(
+                    listeners_.begin(),
+                    listeners_.end(),
+                    [u](const auto &l) { return l->port() == u.getPort(); })) {
+                throw FTL_Error("Cannot connect to self");
+            }
+        }
+    }
+
+    auto p = std::make_shared<Peer>(u, this, &disp_);
+
+    _insertPeer(p);
+    _installBindings(p);
+    p->start();
 
-	// Check if already connected or if self (when could this happen?)
-	{
-		SHARED_LOCK(net_mutex_,lk);
-		if (peer_by_uri_.find(u.getBaseURI()) != peer_by_uri_.end()) {
-			return peers_[peer_by_uri_.at(u.getBaseURI())];
-		}
-
-		if (u.getHost() == "localhost" || u.getHost() == "127.0.0.1") {
-			if (std::any_of(listeners_.begin(), listeners_.end(), [u](const auto &l) { return l->port() == u.getPort(); })) {
-				throw FTL_Error("Cannot connect to self");
-			}
-		}
-	}
-	
-	auto p = std::make_shared<Peer>(u, this, &disp_);
-	
-	_insertPeer(p);
-	_installBindings(p);
-	p->start();
-
-	return p;
+    return p;
 }
 
 PeerPtr Universe::connect(const std::string& addr) {
-	return connect(ftl::URI(addr));
+    return connect(ftl::URI(addr));
 }
 
 void Universe::unbind(const std::string &name) {
-	UNIQUE_LOCK(net_mutex_,lk);
-	disp_.unbind(name);
+    UNIQUE_LOCK(net_mutex_, lk);
+    disp_.unbind(name);
 }
 
 int Universe::waitConnections(int seconds) {
-	SHARED_LOCK(net_mutex_, lk);
-	auto peers = peers_;
-	lk.unlock();
-	return std::count_if(peers.begin(), peers.end(), [seconds](const auto &p) {
-		return p && p->waitConnection(seconds);
-	});
+    SHARED_LOCK(net_mutex_, lk);
+    auto peers = peers_;
+    lk.unlock();
+    return std::count_if(peers.begin(), peers.end(), [seconds](const auto &p) {
+        return p && p->waitConnection(seconds);
+    });
 }
 
 void Universe::_setDescriptors() {
-	SHARED_LOCK(net_mutex_, lk);
-
-	impl_->pollfds.clear();
-	impl_->idMap.clear();
-
-	//Set file descriptor for the listening sockets.
-	for (auto &l : listeners_) {
-		if (l) {
-			auto sock = l->fd();
-			if (sock != INVALID_SOCKET) {
-				pollfd fdentry;
-				#ifdef WIN32
-				fdentry.events = POLLIN;
-				#else
-				fdentry.events = POLLIN; // | POLLERR;
-				#endif
-				fdentry.fd = sock;
-				fdentry.revents = 0;
-				impl_->pollfds.push_back(fdentry);
-				impl_->idMap[sock] = impl_->pollfds.size() - 1;
-			}
-		}
-	}
-
-	//Set the file descriptors for each client
-	for (const auto &s : peers_) {
-		if (s && s->isValid()) {
-			auto sock = s->_socket();
-			if (sock != INVALID_SOCKET) {
-				pollfd fdentry;
-				#ifdef WIN32
-				fdentry.events = POLLIN;
-				#else
-				fdentry.events = POLLIN; // | POLLERR;
-				#endif
-				fdentry.fd = sock;
-				fdentry.revents = 0;
-				impl_->pollfds.push_back(fdentry);
-				impl_->idMap[sock] = impl_->pollfds.size() - 1;
-			}
-		}
-	}
-}
-
-void Universe::_installBindings(const PeerPtr &p) {
-	
-}
-
-void Universe::_installBindings() {
-
-}
+    SHARED_LOCK(net_mutex_, lk);
+
+    impl_->pollfds.clear();
+    impl_->idMap.clear();
+
+    // Set file descriptor for the listening sockets.
+    for (auto &l : listeners_) {
+        if (l) {
+            auto sock = l->fd();
+            if (sock != INVALID_SOCKET) {
+                pollfd fdentry;
+                #ifdef WIN32
+                fdentry.events = POLLIN;
+                #else
+                fdentry.events = POLLIN;  // | POLLERR;
+                #endif
+                fdentry.fd = sock;
+                fdentry.revents = 0;
+                impl_->pollfds.push_back(fdentry);
+                impl_->idMap[sock] = impl_->pollfds.size() - 1;
+            }
+        }
+    }
+
+    // Set the file descriptors for each client
+    for (const auto &s : peers_) {
+        if (s && s->isValid()) {
+            auto sock = s->_socket();
+            if (sock != INVALID_SOCKET) {
+                pollfd fdentry;
+                #ifdef WIN32
+                fdentry.events = POLLIN;
+                #else
+                fdentry.events = POLLIN;  // | POLLERR;
+                #endif
+                fdentry.fd = sock;
+                fdentry.revents = 0;
+                impl_->pollfds.push_back(fdentry);
+                impl_->idMap[sock] = impl_->pollfds.size() - 1;
+            }
+        }
+    }
+}
+
+void Universe::_installBindings(const PeerPtr &p) {}
+
+void Universe::_installBindings() {}
 
 void Universe::_removePeer(PeerPtr &p) {
-	UNIQUE_LOCK(net_mutex_, ulk);
-			
-	if (p && (!p->isValid() ||
-		p->status() == NodeStatus::kReconnecting ||
-		p->status() == NodeStatus::kDisconnected)) {
+    UNIQUE_LOCK(net_mutex_, ulk);
 
-		auto ix = peer_ids_.find(p->id());
-		if (ix != peer_ids_.end()) peer_ids_.erase(ix);
+    if (p && (!p->isValid() ||
+            p->status() == NodeStatus::kReconnecting ||
+            p->status() == NodeStatus::kDisconnected)) {
+        auto ix = peer_ids_.find(p->id());
+        if (ix != peer_ids_.end()) peer_ids_.erase(ix);
 
-		for (auto j=peer_by_uri_.begin(); j != peer_by_uri_.end(); ++j) {
-			if (peers_[j->second] == p) {
-				peer_by_uri_.erase(j);
-				break;
-			}
-		}
+        for (auto j=peer_by_uri_.begin(); j != peer_by_uri_.end(); ++j) {
+            if (peers_[j->second] == p) {
+                peer_by_uri_.erase(j);
+                break;
+            }
+        }
 
-		if (p->status() == NodeStatus::kReconnecting) {
-			reconnects_.push_back({reconnect_attempts_, 1.0f, p});
-		} else {
-			garbage_.push_back(p);
-		}
+        if (p->status() == NodeStatus::kReconnecting) {
+            reconnects_.push_back({reconnect_attempts_, 1.0f, p});
+        } else {
+            garbage_.push_back(p);
+        }
 
-		--connection_count_;
+        --connection_count_;
 
-		DLOG(1) << "Removing disconnected peer: " << p->id().to_string();
-		on_disconnect_.triggerAsync(p);
+        DLOG(1) << "Removing disconnected peer: " << p->id().to_string();
+        on_disconnect_.triggerAsync(p);
 
-		p.reset();
-	}
+        p.reset();
+    }
 }
 
 void Universe::_cleanupPeers() {
-	SHARED_LOCK(net_mutex_, lk);
-	auto i = peers_.begin();
-	while (i != peers_.end()) {
-		auto &p = *i;
-		if (p && (!p->isValid() ||
-			p->status() == NodeStatus::kReconnecting ||
-			p->status() == NodeStatus::kDisconnected)) {
-			lk.unlock();
-			_removePeer(p);
-			lk.lock();
-		}
-		++i;
-	}
+    SHARED_LOCK(net_mutex_, lk);
+    auto i = peers_.begin();
+    while (i != peers_.end()) {
+        auto &p = *i;
+        if (p && (!p->isValid() ||
+            p->status() == NodeStatus::kReconnecting ||
+            p->status() == NodeStatus::kDisconnected)) {
+            lk.unlock();
+            _removePeer(p);
+            lk.lock();
+        }
+        ++i;
+    }
 }
 
 PeerPtr Universe::getPeer(const UUID &id) const {
-	SHARED_LOCK(net_mutex_,lk);
-	auto ix = peer_ids_.find(id);
-	if (ix == peer_ids_.end()) return nullptr;
-	else return peers_[ix->second];
+    SHARED_LOCK(net_mutex_, lk);
+    auto ix = peer_ids_.find(id);
+    if (ix == peer_ids_.end()) return nullptr;
+    else
+        return peers_[ix->second];
 }
 
 PeerPtr Universe::getWebService() const {
-	SHARED_LOCK(net_mutex_,lk);
-	auto it = std::find_if(peers_.begin(), peers_.end(), [](const auto &p) {
-		return p && p->getType() == NodeType::kWebService;
-	});
-	return (it != peers_.end()) ? *it : nullptr;
+    SHARED_LOCK(net_mutex_, lk);
+    auto it = std::find_if(peers_.begin(), peers_.end(), [](const auto &p) {
+        return p && p->getType() == NodeType::kWebService;
+    });
+    return (it != peers_.end()) ? *it : nullptr;
 }
 
 std::list<PeerPtr> Universe::getPeers() const {
-	SHARED_LOCK(net_mutex_,lk);
-	std::list<PeerPtr> result;
-	std::copy_if(peers_.begin(), peers_.end(), std::back_inserter(result), [](const PeerPtr &ptr){ return !!ptr; });
-	return result;
+    SHARED_LOCK(net_mutex_, lk);
+    std::list<PeerPtr> result;
+    std::copy_if(peers_.begin(), peers_.end(), std::back_inserter(result), [](const PeerPtr &ptr){ return !!ptr; });
+    return result;
 }
 
 void Universe::_periodic() {
-	auto i = reconnects_.begin();
-	while (i != reconnects_.end()) {
-
-		std::string addr = i->peer->getURI();
-
-		{
-			SHARED_LOCK(net_mutex_,lk);
-			ftl::URI u(addr);
-			bool removed = false;
-
-			if (u.getHost() == "localhost" || u.getHost() == "127.0.0.1") {
-				for (const auto &l : listeners_) {
-					if (l->port() == u.getPort()) {
-						_notifyError(nullptr, ftl::protocol::Error::kSelfConnect, "Cannot connect to self");
-						garbage_.push_back((*i).peer);
-						i = reconnects_.erase(i);
-						removed = true;
-						break;
-					}
-				}
-			}
-
-			if (removed) continue;
-		}
-
-		auto peer = i->peer;
-		_insertPeer(peer);
-		peer->status_ = NodeStatus::kConnecting;
-		i = reconnects_.erase(i);
-		//ftl::pool.push([peer](int id) {
-			peer->reconnect();
-		//});
-
-		/*if ((*i).peer->reconnect()) {
-			_insertPeer((*i).peer);
-			i = reconnects_.erase(i);
-		}
-		else if ((*i).tries > 0) {
-			(*i).tries--;
-			i++;
-		}
-		 else {
-			garbage_.push_back((*i).peer);
-			i = reconnects_.erase(i);
-		}*/
-	}
+    auto i = reconnects_.begin();
+    while (i != reconnects_.end()) {
+        std::string addr = i->peer->getURI();
+
+        {
+            SHARED_LOCK(net_mutex_, lk);
+            ftl::URI u(addr);
+            bool removed = false;
+
+            if (u.getHost() == "localhost" || u.getHost() == "127.0.0.1") {
+                for (const auto &l : listeners_) {
+                    if (l->port() == u.getPort()) {
+                        _notifyError(nullptr, ftl::protocol::Error::kSelfConnect, "Cannot connect to self");
+                        garbage_.push_back((*i).peer);
+                        i = reconnects_.erase(i);
+                        removed = true;
+                        break;
+                    }
+                }
+            }
+
+            if (removed) continue;
+        }
+
+        auto peer = i->peer;
+        _insertPeer(peer);
+        peer->status_ = NodeStatus::kConnecting;
+        i = reconnects_.erase(i);
+        // ftl::pool.push([peer](int id) {
+            peer->reconnect();
+        // });
+
+        /*if ((*i).peer->reconnect()) {
+            _insertPeer((*i).peer);
+            i = reconnects_.erase(i);
+        }
+        else if ((*i).tries > 0) {
+            (*i).tries--;
+            i++;
+        }
+         else {
+            garbage_.push_back((*i).peer);
+            i = reconnects_.erase(i);
+        }*/
+    }
 }
 
 void Universe::__start(Universe *u) {
 #ifndef WIN32
-	// TODO: move somewhere else (common initialization file?)
-	signal(SIGPIPE,SIG_IGN);
+    // TODO(Seb): move somewhere else (common initialization file?)
+    signal(SIGPIPE, SIG_IGN);
 #endif  // WIN32
-	u->_run();
+    u->_run();
 }
 
 void Universe::_run() {
-	auto start = std::chrono::high_resolution_clock::now();
-
-	while (active_) {
-		_setDescriptors();
-		int selres = 1;
-
-		_cleanupPeers();
-
-		// Do periodics
-		auto now = std::chrono::high_resolution_clock::now();
-		std::chrono::duration<double> elapsed = now - start;
-		if (elapsed.count() >= periodic_time_) {
-			start = now;
-			_periodic();
-		}
-
-		// It is an error to use "select" with no sockets ... so just sleep
-		if (impl_->pollfds.size() == 0) {
-			std::shared_lock lk(net_mutex_);
-			socket_cv_.wait_for(lk, std::chrono::milliseconds(100), [this](){ return listeners_.size() > 0 || connection_count_ > 0; });
-			continue;
-		}
-
-		#ifdef WIN32
-		selres = WSAPoll(impl_->pollfds.data(), impl_->pollfds.size(), 100);
-		#else
-		selres = poll(impl_->pollfds.data(), impl_->pollfds.size(), 100);
-		#endif
-
-		//Some kind of error occured, it is usually possible to recover from this.
-		if (selres < 0) {
-			#ifdef WIN32
-			int errNum = WSAGetLastError();
-			switch (errNum) {
-			case WSAENOTSOCK	: continue;  // Socket was closed
-			default				: DLOG(WARNING) << "Unhandled poll error: " << errNum;
-			}
-			#else
-			switch (errno) {
-			case 9	: continue;  // Bad file descriptor = socket closed
-			case 4	: continue;  // Interrupted system call ... no problem
-			default	: DLOG(WARNING) << "Unhandled poll error: " << strerror(errno) << "(" << errno << ")";
-			}
-			#endif
-			continue;
-		} else if (selres == 0) {
-			// Timeout, nothing to do...
-			continue;
-		}
-
-		SHARED_LOCK(net_mutex_,lk);
-
-		//If connection request is waiting
-		for (auto &l : listeners_) {
-			if (l && l->is_listening() && (impl_->pollfds[impl_->idMap[l->fd()]].revents & POLLIN)) {
-				std::unique_ptr<ftl::net::internal::SocketConnection> csock;
-				try {
-					csock = l->accept();
-				} catch (const std::exception &ex) {
-					_notifyError(nullptr, ftl::protocol::Error::kConnectionFailed, ex.what());
-				}
-
-				lk.unlock();
-
-				if (csock) {
-					auto p = std::make_shared<Peer>(std::move(csock), this, &disp_);
-					_insertPeer(p);
-					p->start();
-				}
-
-				lk.lock();
-			}
-		}
-
-
-		// Also check each clients socket to see if any messages or errors are waiting
-		for (size_t p=0; p<peers_.size(); ++p) {
-			auto s = peers_[(p+phase_)%peers_.size()];
-
-			if (s && s->isValid()) {
-				// Note: It is possible that the socket becomes invalid after check but before
-				// looking at the FD sets, therefore cache the original socket
-				SOCKET sock = s->_socket();
-				if (sock == INVALID_SOCKET) continue;
-
-				if (impl_->idMap.count(sock) == 0) continue;
-
-				const auto &fdstruct = impl_->pollfds[impl_->idMap[sock]];
-
-				// This is needed on Windows to detect socket close.
-				if (fdstruct.revents & POLLERR) {
-					if (s->socketError()) {
-						//lk.unlock();
-						//s->close();
-						//lk.lock();
-						continue;  // No point in reading data...
-					}
-				}
-				//If message received from this client then deal with it
-				if (fdstruct.revents & POLLIN) {
-					lk.unlock();
-					s->data();
-					lk.lock();
-				}
-			}
-		}
-		++phase_;
-	}
-
-	// Garbage is a threadsafe container, moving there first allows the destructor to be called
-	// without the lock.
-	{
-		UNIQUE_LOCK(net_mutex_,lk);
-		garbage_.insert(garbage_.end(), peers_.begin(), peers_.end());
-		reconnects_.clear();
-		peers_.clear();
-		peer_by_uri_.clear();
-		peer_ids_.clear();
-		listeners_.clear();
-	}
-
-	garbage_.clear();
+    auto start = std::chrono::high_resolution_clock::now();
+
+    while (active_) {
+        _setDescriptors();
+        int selres = 1;
+
+        _cleanupPeers();
+
+        // Do periodics
+        auto now = std::chrono::high_resolution_clock::now();
+        std::chrono::duration<double> elapsed = now - start;
+        if (elapsed.count() >= periodic_time_) {
+            start = now;
+            _periodic();
+        }
+
+        // It is an error to use "select" with no sockets ... so just sleep
+        if (impl_->pollfds.size() == 0) {
+            std::shared_lock lk(net_mutex_);
+            socket_cv_.wait_for(
+                lk,
+                milliseconds(100),
+                [this](){ return listeners_.size() > 0 || connection_count_ > 0; });
+            continue;
+        }
+
+        #ifdef WIN32
+        selres = WSAPoll(impl_->pollfds.data(), impl_->pollfds.size(), 100);
+        #else
+        selres = poll(impl_->pollfds.data(), impl_->pollfds.size(), 100);
+        #endif
+
+        // Some kind of error occured, it is usually possible to recover from this.
+        if (selres < 0) {
+            #ifdef WIN32
+            int errNum = WSAGetLastError();
+            switch (errNum) {
+            case WSAENOTSOCK    : continue;  // Socket was closed
+            default             : DLOG(WARNING) << "Unhandled poll error: " << errNum;
+            }
+            #else
+            switch (errno) {
+            case 9  : continue;  // Bad file descriptor = socket closed
+            case 4  : continue;  // Interrupted system call ... no problem
+            default : DLOG(WARNING) << "Unhandled poll error: " << strerror(errno) << "(" << errno << ")";
+            }
+            #endif
+            continue;
+        } else if (selres == 0) {
+            // Timeout, nothing to do...
+            continue;
+        }
+
+        SHARED_LOCK(net_mutex_, lk);
+
+        // If connection request is waiting
+        for (auto &l : listeners_) {
+            if (l && l->is_listening() && (impl_->pollfds[impl_->idMap[l->fd()]].revents & POLLIN)) {
+                std::unique_ptr<ftl::net::internal::SocketConnection> csock;
+                try {
+                    csock = l->accept();
+                } catch (const std::exception &ex) {
+                    _notifyError(nullptr, ftl::protocol::Error::kConnectionFailed, ex.what());
+                }
+
+                lk.unlock();
+
+                if (csock) {
+                    auto p = std::make_shared<Peer>(std::move(csock), this, &disp_);
+                    _insertPeer(p);
+                    p->start();
+                }
+
+                lk.lock();
+            }
+        }
+
+
+        // Also check each clients socket to see if any messages or errors are waiting
+        for (size_t p = 0; p < peers_.size(); ++p) {
+            auto s = peers_[(p+phase_)%peers_.size()];
+
+            if (s && s->isValid()) {
+                // Note: It is possible that the socket becomes invalid after check but before
+                // looking at the FD sets, therefore cache the original socket
+                SOCKET sock = s->_socket();
+                if (sock == INVALID_SOCKET) continue;
+
+                if (impl_->idMap.count(sock) == 0) continue;
+
+                const auto &fdstruct = impl_->pollfds[impl_->idMap[sock]];
+
+                // This is needed on Windows to detect socket close.
+                if (fdstruct.revents & POLLERR) {
+                    if (s->socketError()) {
+                        continue;  // No point in reading data...
+                    }
+                }
+                // If message received from this client then deal with it
+                if (fdstruct.revents & POLLIN) {
+                    lk.unlock();
+                    s->data();
+                    lk.lock();
+                }
+            }
+        }
+        ++phase_;
+    }
+
+    // Garbage is a threadsafe container, moving there first allows the destructor to be called
+    // without the lock.
+    {
+        UNIQUE_LOCK(net_mutex_, lk);
+        garbage_.insert(garbage_.end(), peers_.begin(), peers_.end());
+        reconnects_.clear();
+        peers_.clear();
+        peer_by_uri_.clear();
+        peer_ids_.clear();
+        listeners_.clear();
+    }
+
+    garbage_.clear();
 }
 
 ftl::Handle Universe::onConnect(const std::function<bool(const PeerPtr&)> &cb) {
-	return on_connect_.on(cb);
+    return on_connect_.on(cb);
 }
 
 ftl::Handle Universe::onDisconnect(const std::function<bool(const PeerPtr&)> &cb) {
-	return on_disconnect_.on(cb);
+    return on_disconnect_.on(cb);
 }
 
-ftl::Handle Universe::onError(const std::function<bool(const PeerPtr&, ftl::protocol::Error, const std::string &)> &cb) {
-	return on_error_.on(cb);
+ftl::Handle Universe::onError(
+        const std::function<bool(const PeerPtr&, ftl::protocol::Error, const std::string &)> &cb) {
+    return on_error_.on(cb);
 }
 
 PeerPtr Universe::injectFakePeer(std::unique_ptr<ftl::net::internal::SocketConnection> s) {
-	auto p = std::make_shared<Peer>(std::move(s), this, &disp_);
-	_insertPeer(p);
-	_installBindings(p);
-	return p;
+    auto p = std::make_shared<Peer>(std::move(s), this, &disp_);
+    _insertPeer(p);
+    _installBindings(p);
+    return p;
 }
 
 PeerPtr Universe::_findPeer(const Peer *p) {
-	SHARED_LOCK(net_mutex_,lk);
-	for (const auto &pp : peers_) {
-		if (pp.get() == p) return pp;
-	}
-	return nullptr;
+    SHARED_LOCK(net_mutex_, lk);
+    for (const auto &pp : peers_) {
+        if (pp.get() == p) return pp;
+    }
+    return nullptr;
 }
 
 void Universe::_notifyConnect(Peer *p) {
-	const auto ptr = _findPeer(p);
+    const auto ptr = _findPeer(p);
 
-	// The peer could have been removed from valid peers already.
-	if (!ptr) return;
+    // The peer could have been removed from valid peers already.
+    if (!ptr) return;
 
-	{
-		UNIQUE_LOCK(net_mutex_,lk);
-		peer_ids_[ptr->id()] = ptr->local_id_;
-	}
+    {
+        UNIQUE_LOCK(net_mutex_, lk);
+        peer_ids_[ptr->id()] = ptr->local_id_;
+    }
 
-	on_connect_.triggerAsync(ptr);
+    on_connect_.triggerAsync(ptr);
 }
 
 void Universe::_notifyDisconnect(Peer *p) {
-	const auto ptr = _findPeer(p);
-	if (!ptr) return;
+    const auto ptr = _findPeer(p);
+    if (!ptr) return;
 
-	on_disconnect_.triggerAsync(ptr);
+    on_disconnect_.triggerAsync(ptr);
 }
 
 void Universe::_notifyError(Peer *p, ftl::protocol::Error e, const std::string &errstr) {
-	LOG(ERROR) << "Net Error (" << int(e) << "): " << errstr;
-	const auto ptr = (p) ? _findPeer(p) : nullptr;
-
-	// Note: Net errors can have no peer
-	//if (!ptr) return;
+    LOG(ERROR) << "Net Error (" << int(e) << "): " << errstr;
+    const auto ptr = (p) ? _findPeer(p) : nullptr;
 
-	on_error_.triggerAsync(ptr, e, errstr);
+    on_error_.triggerAsync(ptr, e, errstr);
 }
diff --git a/src/universe.hpp b/src/universe.hpp
index 439c8d724a33336e0638015a10a9ae20fba2d9e2..942557b355345af9c2ba43263be4e253d8e025ba 100644
--- a/src/universe.hpp
+++ b/src/universe.hpp
@@ -6,6 +6,14 @@
 
 #pragma once
 
+#include <vector>
+#include <list>
+#include <string>
+#include <thread>
+#include <map>
+#include <unordered_map>
+#include <memory>
+
 #include <msgpack.hpp>
 
 #include <ftl/protocol.hpp>
@@ -19,23 +27,13 @@
 
 #include <nlohmann/json_fwd.hpp>
 
-#include <vector>
-#include <list>
-#include <string>
-#include <thread>
-#include <map>
-
 namespace ftl {
 namespace net {
 
-struct Error {
-	int errno;
-};
-
 struct ReconnectInfo {
-	int tries;
-	float delay;
-	PeerPtr peer;
+    int tries;
+    float delay;
+    PeerPtr peer;
 };
 
 struct NetImplDetail;
@@ -52,314 +50,316 @@ using Callback = unsigned int;
  * their actions.
  */
 class Universe {
-public:
-	friend class Peer;
-
-	Universe();
-
-	/**
-	 * The destructor will terminate the network thread before completing.
-	 */
-	~Universe();
-
-	void start();
-	
-	/**
-	 * Open a new listening port on a given interfaces.
-	 *   eg. "tcp://localhost:9000"
-	 * @param addr URI giving protocol, interface and port
-	 */
-	bool listen(const ftl::URI &addr);
-
-	std::vector<ftl::URI> getListeningURIs();
-
-	/**
-	 * Essential to call this before destroying anything that registered
-	 * callbacks or binds for RPC. It will terminate all connections and
-	 * stop any network activity but without deleting the net object.
-	 */
-	void shutdown();
-	
-	/**
-	 * Create a new peer connection.
-	 *   eg. "tcp://10.0.0.2:9000"
-	 * Supported protocols include tcp and ws.
-	 *
-	 * @param addr URI giving protocol, interface and port
-	 */
-	PeerPtr connect(const std::string &addr);
-	PeerPtr connect(const ftl::URI &addr);
-
-	bool isConnected(const ftl::URI &uri);
-	bool isConnected(const std::string &s);
-	
-	size_t numberOfPeers() const { return connection_count_; }
-
-	/**
-	 * Will block until all currently registered connnections have completed.
-	 * You should not use this, but rather use onConnect.
-	 */
-	int waitConnections(int seconds = 1);
-	
-	/** get peer pointer by peer UUID, returns nullptr if not found */
-	PeerPtr getPeer(const ftl::UUID &pid) const;
-	/** get webservice peer pointer, returns nullptr if not connected to webservice */
-	PeerPtr getWebService() const;
-
-	std::list<PeerPtr> getPeers() const;
-
-	/**
-	 * Bind a function to an RPC or service call name. This will implicitely
-	 * be called by any peer making the request.
-	 */
-	template <typename F>
-	void bind(const std::string &name, F func);
-
-	void unbind(const std::string &name);
-
-	/**
-	 * Check if an RPC name is already bound.
-	 */
-	inline bool isBound(const std::string &name) const { return disp_.isBound(name); }
-	
-	/**
-	 * Send a non-blocking RPC call with no return value to all connected
-	 * peers.
-	 */
-	template <typename... ARGS>
-	void broadcast(const std::string &name, ARGS... args);
-	
-	template <typename R, typename... ARGS>
-	R call(const UUID &pid, const std::string &name, ARGS... args);
-
-	/**
-	 * Non-blocking Remote Procedure Call using a callback function.
-	 * 
-	 * @param pid Peer GUID
-	 * @param name RPC Function name.
-	 * @param cb Completion callback.
-	 * @param args A variable number of arguments for RPC function.
-	 * 
-	 * @return A call id for use with cancelCall() if needed.
-	 */
-	template <typename R, typename... ARGS>
-	int asyncCall(const UUID &pid, const std::string &name,
-			std::function<void(const R&)> cb,
-			ARGS... args);
-	
-	template <typename... ARGS>
-	bool send(const UUID &pid, const std::string &name, ARGS... args);
-
-	template <typename... ARGS>
-	int try_send(const UUID &pid, const std::string &name, ARGS... args);
-
-	template <typename R, typename... ARGS>
-	std::optional<R> findOne(const std::string &name, ARGS... args);
-
-	template <typename R, typename... ARGS>
-	std::vector<R> findAll(const std::string &name, ARGS... args);
-
-	void setLocalID(const ftl::UUID &u) { this_peer = u; };
-	const ftl::UUID &id() const { return this_peer; }
-
-	// --- Event Handlers -----------------------------------------------------
-
-	ftl::Handle onConnect(const std::function<bool(const ftl::net::PeerPtr&)>&);
-	ftl::Handle onDisconnect(const std::function<bool(const ftl::net::PeerPtr&)>&);
-	ftl::Handle onError(const std::function<bool(const ftl::net::PeerPtr&, ftl::protocol::Error, const std::string &)>&);
-
-	size_t getSendBufferSize(ftl::URI::scheme_t s);
-	size_t getRecvBufferSize(ftl::URI::scheme_t s);
-
-	static inline std::shared_ptr<Universe> getInstance() { return instance_; }
-
-	// --- Test support -------------------------------------------------------
-
-	PeerPtr injectFakePeer(std::unique_ptr<ftl::net::internal::SocketConnection> s);
-	
-private:
-	void _run();
-	void _setDescriptors();
-	void _installBindings();
-	void _installBindings(const ftl::net::PeerPtr&);
-	void _cleanupPeers();
-	void _notifyConnect(ftl::net::Peer *);
-	void _notifyDisconnect(ftl::net::Peer *);
-	void _notifyError(ftl::net::Peer *, ftl::protocol::Error, const std::string &);
-	void _periodic();
-	ftl::net::PeerPtr _findPeer(const ftl::net::Peer *p);
-	void _removePeer(PeerPtr &p);
-	void _insertPeer(const ftl::net::PeerPtr &ptr);
-	
-	static void __start(Universe *u);
-	
-	bool active_;
-	ftl::UUID this_peer;
-	mutable SHARED_MUTEX net_mutex_;
-	std::condition_variable_any socket_cv_;
-	
-	std::unique_ptr<NetImplDetail> impl_;
-	
-	std::vector<std::unique_ptr<ftl::net::internal::SocketServer>> listeners_;
-	std::vector<ftl::net::PeerPtr> peers_;
-	std::unordered_map<std::string, size_t> peer_by_uri_;
-	std::map<ftl::UUID, size_t> peer_ids_;
-
-	ftl::net::Dispatcher disp_;
-	std::list<ReconnectInfo> reconnects_;
-	size_t phase_;
-	std::list<ftl::net::PeerPtr> garbage_;
-	ftl::Handle garbage_timer_;
-
-	// size_t send_size_;
-	// size_t recv_size_;
-	double periodic_time_;
-	int reconnect_attempts_;
-	std::atomic_int connection_count_ = 0;	// Active connections
-	std::atomic_int peer_instances_ = 0;	// Actual peers dependent on Universe
-
-	ftl::Handler<const ftl::net::PeerPtr&> on_connect_;
-	ftl::Handler<const ftl::net::PeerPtr&> on_disconnect_;
-	ftl::Handler<const ftl::net::PeerPtr&, ftl::protocol::Error, const std::string &> on_error_;
-
-	static std::shared_ptr<Universe> instance_;
-
-	// NOTE: Must always be last member
-	std::thread thread_;
+ public:
+    friend class Peer;
+
+    Universe();
+
+    /**
+     * The destructor will terminate the network thread before completing.
+     */
+    ~Universe();
+
+    void start();
+
+    /**
+     * Open a new listening port on a given interfaces.
+     *   eg. "tcp://localhost:9000"
+     * @param addr URI giving protocol, interface and port
+     */
+    bool listen(const ftl::URI &addr);
+
+    std::vector<ftl::URI> getListeningURIs();
+
+    /**
+     * Essential to call this before destroying anything that registered
+     * callbacks or binds for RPC. It will terminate all connections and
+     * stop any network activity but without deleting the net object.
+     */
+    void shutdown();
+
+    /**
+     * Create a new peer connection.
+     *   eg. "tcp://10.0.0.2:9000"
+     * Supported protocols include tcp and ws.
+     *
+     * @param addr URI giving protocol, interface and port
+     */
+    PeerPtr connect(const std::string &addr);
+    PeerPtr connect(const ftl::URI &addr);
+
+    bool isConnected(const ftl::URI &uri);
+    bool isConnected(const std::string &s);
+
+    size_t numberOfPeers() const { return connection_count_; }
+
+    /**
+     * Will block until all currently registered connnections have completed.
+     * You should not use this, but rather use onConnect.
+     */
+    int waitConnections(int seconds = 1);
+
+    /** get peer pointer by peer UUID, returns nullptr if not found */
+    PeerPtr getPeer(const ftl::UUID &pid) const;
+    /** get webservice peer pointer, returns nullptr if not connected to webservice */
+    PeerPtr getWebService() const;
+
+    std::list<PeerPtr> getPeers() const;
+
+    /**
+     * Bind a function to an RPC or service call name. This will implicitely
+     * be called by any peer making the request.
+     */
+    template <typename F>
+    void bind(const std::string &name, F func);
+
+    void unbind(const std::string &name);
+
+    /**
+     * Check if an RPC name is already bound.
+     */
+    inline bool isBound(const std::string &name) const { return disp_.isBound(name); }
+
+    /**
+     * Send a non-blocking RPC call with no return value to all connected
+     * peers.
+     */
+    template <typename... ARGS>
+    void broadcast(const std::string &name, ARGS... args);
+
+    template <typename R, typename... ARGS>
+    R call(const UUID &pid, const std::string &name, ARGS... args);
+
+    /**
+     * Non-blocking Remote Procedure Call using a callback function.
+     * 
+     * @param pid Peer GUID
+     * @param name RPC Function name.
+     * @param cb Completion callback.
+     * @param args A variable number of arguments for RPC function.
+     * 
+     * @return A call id for use with cancelCall() if needed.
+     */
+    template <typename R, typename... ARGS>
+    int asyncCall(const UUID &pid, const std::string &name,
+            std::function<void(const R&)> cb,
+            ARGS... args);
+
+    template <typename... ARGS>
+    bool send(const UUID &pid, const std::string &name, ARGS... args);
+
+    template <typename... ARGS>
+    int try_send(const UUID &pid, const std::string &name, ARGS... args);
+
+    template <typename R, typename... ARGS>
+    std::optional<R> findOne(const std::string &name, ARGS... args);
+
+    template <typename R, typename... ARGS>
+    std::vector<R> findAll(const std::string &name, ARGS... args);
+
+    void setLocalID(const ftl::UUID &u) { this_peer = u; }
+    const ftl::UUID &id() const { return this_peer; }
+
+    // --- Event Handlers -----------------------------------------------------
+
+    ftl::Handle onConnect(const std::function<bool(const ftl::net::PeerPtr&)>&);
+    ftl::Handle onDisconnect(const std::function<bool(const ftl::net::PeerPtr&)>&);
+    ftl::Handle onError(
+        const std::function<bool(const ftl::net::PeerPtr&, ftl::protocol::Error, const std::string &)>&);
+
+    size_t getSendBufferSize(ftl::URI::scheme_t s);
+    size_t getRecvBufferSize(ftl::URI::scheme_t s);
+
+    static inline std::shared_ptr<Universe> getInstance() { return instance_; }
+
+    // --- Test support -------------------------------------------------------
+
+    PeerPtr injectFakePeer(std::unique_ptr<ftl::net::internal::SocketConnection> s);
+
+ private:
+    void _run();
+    void _setDescriptors();
+    void _installBindings();
+    void _installBindings(const ftl::net::PeerPtr&);
+    void _cleanupPeers();
+    void _notifyConnect(ftl::net::Peer *);
+    void _notifyDisconnect(ftl::net::Peer *);
+    void _notifyError(ftl::net::Peer *, ftl::protocol::Error, const std::string &);
+    void _periodic();
+    ftl::net::PeerPtr _findPeer(const ftl::net::Peer *p);
+    void _removePeer(PeerPtr &p);
+    void _insertPeer(const ftl::net::PeerPtr &ptr);
+
+    static void __start(Universe *u);
+
+    bool active_;
+    ftl::UUID this_peer;
+    mutable SHARED_MUTEX net_mutex_;
+    std::condition_variable_any socket_cv_;
+
+    std::unique_ptr<NetImplDetail> impl_;
+
+    std::vector<std::unique_ptr<ftl::net::internal::SocketServer>> listeners_;
+    std::vector<ftl::net::PeerPtr> peers_;
+    std::unordered_map<std::string, size_t> peer_by_uri_;
+    std::map<ftl::UUID, size_t> peer_ids_;
+
+    ftl::net::Dispatcher disp_;
+    std::list<ReconnectInfo> reconnects_;
+    size_t phase_;
+    std::list<ftl::net::PeerPtr> garbage_;
+    ftl::Handle garbage_timer_;
+
+    // size_t send_size_;
+    // size_t recv_size_;
+    double periodic_time_;
+    int reconnect_attempts_;
+    std::atomic_int connection_count_ = 0;  // Active connections
+    std::atomic_int peer_instances_ = 0;    // Actual peers dependent on Universe
+
+    ftl::Handler<const ftl::net::PeerPtr&> on_connect_;
+    ftl::Handler<const ftl::net::PeerPtr&> on_disconnect_;
+    ftl::Handler<const ftl::net::PeerPtr&, ftl::protocol::Error, const std::string &> on_error_;
+
+    static std::shared_ptr<Universe> instance_;
+
+    // NOTE: Must always be last member
+    std::thread thread_;
 };
 
 //------------------------------------------------------------------------------
 
 template <typename F>
 void Universe::bind(const std::string &name, F func) {
-	UNIQUE_LOCK(net_mutex_,lk);
-	disp_.bind(name, func,
-		typename ftl::internal::func_kind_info<F>::result_kind(),
-		typename ftl::internal::func_kind_info<F>::args_kind(),
-		typename ftl::internal::func_kind_info<F>::has_peer());
+    UNIQUE_LOCK(net_mutex_, lk);
+    disp_.bind(name, func,
+        typename ftl::internal::func_kind_info<F>::result_kind(),
+        typename ftl::internal::func_kind_info<F>::args_kind(),
+        typename ftl::internal::func_kind_info<F>::has_peer());
 }
 
 template <typename... ARGS>
 void Universe::broadcast(const std::string &name, ARGS... args) {
-	SHARED_LOCK(net_mutex_,lk);
-	for (const auto &p : peers_) {
-		if (!p || !p->waitConnection()) continue;
-		p->send(name, args...);
-	}
+    SHARED_LOCK(net_mutex_, lk);
+    for (const auto &p : peers_) {
+        if (!p || !p->waitConnection()) continue;
+        p->send(name, args...);
+    }
 }
 
 template <typename R, typename... ARGS>
 std::optional<R> Universe::findOne(const std::string &name, ARGS... args) {
-	struct SharedData {
-		std::atomic_bool hasreturned = false;
-		std::mutex m;
-		std::condition_variable cv;
-		std::optional<R> result;
-	};
-
-	auto sdata = std::make_shared<SharedData>();
-
-	auto handler = [sdata](const std::optional<R> &r) {
-		std::unique_lock<std::mutex> lk(sdata->m);
-		if (r && !sdata->hasreturned) {
-			sdata->hasreturned = true;
-			sdata->result = r;
-		}
-		lk.unlock();
-		sdata->cv.notify_one();
-	};
-
-	{
-		SHARED_LOCK(net_mutex_,lk);
-		for (const auto &p : peers_) {
-			if (!p || !p->waitConnection()) continue;
-			p->asyncCall<std::optional<R>>(name, handler, args...);
-		}
-	}
-	
-	// Block thread until async callback notifies us
-	std::unique_lock<std::mutex> llk(sdata->m);
-	sdata->cv.wait_for(llk, std::chrono::seconds(1), [sdata] {
-		return (bool)sdata->hasreturned;
-	});
-
-	return sdata->result;
+    struct SharedData {
+        std::atomic_bool hasreturned = false;
+        std::mutex m;
+        std::condition_variable cv;
+        std::optional<R> result;
+    };
+
+    auto sdata = std::make_shared<SharedData>();
+
+    auto handler = [sdata](const std::optional<R> &r) {
+        std::unique_lock<std::mutex> lk(sdata->m);
+        if (r && !sdata->hasreturned) {
+            sdata->hasreturned = true;
+            sdata->result = r;
+        }
+        lk.unlock();
+        sdata->cv.notify_one();
+    };
+
+    {
+        SHARED_LOCK(net_mutex_, lk);
+        for (const auto &p : peers_) {
+            if (!p || !p->waitConnection()) continue;
+            p->asyncCall<std::optional<R>>(name, handler, args...);
+        }
+    }
+
+    // Block thread until async callback notifies us
+    std::unique_lock<std::mutex> llk(sdata->m);
+    sdata->cv.wait_for(llk, std::chrono::seconds(1), [sdata] {
+        return static_cast<bool>(sdata->hasreturned);
+    });
+
+    return sdata->result;
 }
 
 template <typename R, typename... ARGS>
 std::vector<R> Universe::findAll(const std::string &name, ARGS... args) {
-	struct SharedData {
-		std::atomic_int returncount = 0;
-		std::atomic_int sentcount = 0;
-		std::mutex m;
-		std::condition_variable cv;
-		std::vector<R> results;
-	};
-
-	auto sdata = std::make_shared<SharedData>();
-
-	auto handler = [sdata](const std::vector<R> &r) {
-		std::unique_lock<std::mutex> lk(sdata->m);
-		++sdata->returncount;
-		sdata->results.insert(sdata->results.end(), r.begin(), r.end());
-		lk.unlock();
-		sdata->cv.notify_one();
-	};
-
-	{
-		SHARED_LOCK(net_mutex_,lk);
-		for (const auto &p : peers_) {
-			if (!p || !p->waitConnection()) continue;
-			++sdata->sentcount;
-			p->asyncCall<std::vector<R>>(name, handler, args...);
-		}
-	}
-	
-	std::unique_lock<std::mutex> llk(sdata->m);
-	sdata->cv.wait_for(llk, std::chrono::seconds(1), [sdata]{return sdata->returncount == sdata->sentcount; });
-	return sdata->results;
+    struct SharedData {
+        std::atomic_int returncount = 0;
+        std::atomic_int sentcount = 0;
+        std::mutex m;
+        std::condition_variable cv;
+        std::vector<R> results;
+    };
+
+    auto sdata = std::make_shared<SharedData>();
+
+    auto handler = [sdata](const std::vector<R> &r) {
+        std::unique_lock<std::mutex> lk(sdata->m);
+        ++sdata->returncount;
+        sdata->results.insert(sdata->results.end(), r.begin(), r.end());
+        lk.unlock();
+        sdata->cv.notify_one();
+    };
+
+    {
+        SHARED_LOCK(net_mutex_, lk);
+        for (const auto &p : peers_) {
+            if (!p || !p->waitConnection()) continue;
+            ++sdata->sentcount;
+            p->asyncCall<std::vector<R>>(name, handler, args...);
+        }
+    }
+
+    std::unique_lock<std::mutex> llk(sdata->m);
+    sdata->cv.wait_for(llk, std::chrono::seconds(1), [sdata]{return sdata->returncount == sdata->sentcount; });
+    return sdata->results;
 }
 
 template <typename R, typename... ARGS>
 R Universe::call(const ftl::UUID &pid, const std::string &name, ARGS... args) {
-	PeerPtr p = getPeer(pid);
-	if (p == nullptr || !p->isConnected()) {
-		if (p == nullptr) throw FTL_Error("Attempting to call an unknown peer : " << pid.to_string());
-		else throw FTL_Error("Attempting to call an disconnected peer : " << pid.to_string());
-	}
-	return p->call<R>(name, args...);
+    PeerPtr p = getPeer(pid);
+    if (p == nullptr || !p->isConnected()) {
+        if (p == nullptr) throw FTL_Error("Attempting to call an unknown peer : " << pid.to_string());
+        else
+            throw FTL_Error("Attempting to call an disconnected peer : " << pid.to_string());
+    }
+    return p->call<R>(name, args...);
 }
 
 template <typename R, typename... ARGS>
 int Universe::asyncCall(const ftl::UUID &pid, const std::string &name, std::function<void(const R&)> cb, ARGS... args) {
-	PeerPtr p = getPeer(pid);
-	if (p == nullptr || !p->isConnected()) {
-		if (p == nullptr) throw FTL_Error("Attempting to call an unknown peer : " << pid.to_string());
-		else throw FTL_Error("Attempting to call an disconnected peer : " << pid.to_string());
-	}
-	return p->asyncCall(name, cb, args...);
+    PeerPtr p = getPeer(pid);
+    if (p == nullptr || !p->isConnected()) {
+        if (p == nullptr) throw FTL_Error("Attempting to call an unknown peer : " << pid.to_string());
+        else
+            throw FTL_Error("Attempting to call an disconnected peer : " << pid.to_string());
+    }
+    return p->asyncCall(name, cb, args...);
 }
 
 template <typename... ARGS>
 bool Universe::send(const ftl::UUID &pid, const std::string &name, ARGS... args) {
-	PeerPtr p = getPeer(pid);
-	if (p == nullptr) {
-		LOG(WARNING) << "Attempting to call an unknown peer : " << pid.to_string();
-		return false;
-	}
+    PeerPtr p = getPeer(pid);
+    if (p == nullptr) {
+        LOG(WARNING) << "Attempting to call an unknown peer : " << pid.to_string();
+        return false;
+    }
 
-	return p->isConnected() && p->send(name, args...) > 0;
+    return p->isConnected() && p->send(name, args...) > 0;
 }
 
 template <typename... ARGS>
 int Universe::try_send(const ftl::UUID &pid, const std::string &name, ARGS... args) {
-	PeerPtr p = getPeer(pid);
-	if (p == nullptr) {
-		//DLOG(WARNING) << "Attempting to call an unknown peer : " << pid.to_string();
-		return false;
-	}
+    PeerPtr p = getPeer(pid);
+    if (p == nullptr) {
+        return false;
+    }
 
-	return (p->isConnected()) ? p->try_send(name, args...) : -1;
+    return (p->isConnected()) ? p->try_send(name, args...) : -1;
 }
 
 };  // namespace net
diff --git a/src/uri.cpp b/src/uri.cpp
index 7432f82c7d245c4ab01dab8fb05bdce2dffbc86c..fcb90dfb1aa2217a79cff38773821ad6618651c1 100644
--- a/src/uri.cpp
+++ b/src/uri.cpp
@@ -4,10 +4,11 @@
  * @author Nicolas Pope
  */
 
+#include <cstdlib>
 #include <ftl/uri.hpp>
 #include <nlohmann/json.hpp>
 // #include <filesystem>  TODO When available
-#include <cstdlib>
+
 #include <ftl/lib/loguru.hpp>
 
 #ifndef WIN32
@@ -21,238 +22,238 @@ using ftl::uri_t;
 using std::string;
 
 URI::URI(uri_t puri) {
-	_parse(puri);
+    _parse(puri);
 }
 
 URI::URI(const std::string &puri) {
-	_parse(puri.c_str());
+    _parse(puri.c_str());
 }
 
 URI::URI(const URI &c) {
-	m_valid = c.m_valid;
-	m_host = c.m_host;
-	m_port = c.m_port;
-	m_proto = c.m_proto;
-	m_path = c.m_path;
-	m_pathseg = c.m_pathseg;
-	m_qmap = c.m_qmap;
-	m_base = c.m_base;
-	m_userinfo = c.m_userinfo;
-	m_frag = c.m_frag;
+    m_valid = c.m_valid;
+    m_host = c.m_host;
+    m_port = c.m_port;
+    m_proto = c.m_proto;
+    m_path = c.m_path;
+    m_pathseg = c.m_pathseg;
+    m_qmap = c.m_qmap;
+    m_base = c.m_base;
+    m_userinfo = c.m_userinfo;
+    m_frag = c.m_frag;
 }
 
 void URI::_parse(uri_t puri) {
-	UriUriA uri;
-
-	std::string suri = puri;
-
-	// NOTE: Non-standard additions to allow for Unix style relative file names.
-	if (suri[0] == '.') {
-		char cwdbuf[1024];
-		if (getcwd(cwdbuf, 1024)) {
-			suri = string("file://") + string(cwdbuf) + suri.substr(1);
-		}
-	} else if (suri[0] == '/') {
-		suri = std::string("file://") + suri;
-	} else if (suri[0] == '~') {
+    UriUriA uri;
+
+    std::string suri = puri;
+
+    // NOTE: Non-standard additions to allow for Unix style relative file names.
+    if (suri[0] == '.') {
+        char cwdbuf[1024];
+        if (getcwd(cwdbuf, 1024)) {
+            suri = string("file://") + string(cwdbuf) + suri.substr(1);
+        }
+    } else if (suri[0] == '/') {
+        suri = std::string("file://") + suri;
+    } else if (suri[0] == '~') {
 #ifdef WIN32
-		suri = string("file://") + string(std::getenv("HOMEDRIVE")) + string(std::getenv("HOMEPATH")) + suri.substr(1);
+        suri = string("file://") + string(std::getenv("HOMEDRIVE")) + string(std::getenv("HOMEPATH")) + suri.substr(1);
 #else
-		suri = string("file://") + string(std::getenv("HOME")) + suri.substr(1);
+        suri = string("file://") + string(std::getenv("HOME")) + suri.substr(1);
 #endif
-	}
+    }
 
 #ifdef HAVE_URIPARSESINGLE
-	const char *errpos;
-	if (uriParseSingleUriA(&uri, puri, &errpos) != URI_SUCCESS) {
+    const char *errpos;
+    if (uriParseSingleUriA(&uri, puri, &errpos) != URI_SUCCESS) {
 #else
-	UriParserStateA uris;
-	uris.uri = &uri;
-	if (uriParseUriA(&uris, suri.c_str()) != URI_SUCCESS) {
+    UriParserStateA uris;
+    uris.uri = &uri;
+    if (uriParseUriA(&uris, suri.c_str()) != URI_SUCCESS) {
 #endif
-		m_valid = false;
-		m_host = "none";
-		m_port = -1;
-		m_proto = SCHEME_NONE;
-		m_base = suri;
-		m_path = "";
-		m_frag = "";
-	} else {
-		m_host = std::string(uri.hostText.first, uri.hostText.afterLast - uri.hostText.first);
-
-		std::string prototext = std::string(uri.scheme.first, uri.scheme.afterLast - uri.scheme.first);
-		if (prototext == "tcp") m_proto = SCHEME_TCP;
-		else if (prototext == "udp") m_proto = SCHEME_UDP;
-		else if (prototext == "ftl") m_proto = SCHEME_FTL;
-		else if (prototext == "http") m_proto = SCHEME_HTTP;
-		else if (prototext == "ws") m_proto = SCHEME_WS;
-		else if (prototext == "wss") m_proto = SCHEME_WSS;
-		else if (prototext == "ipc") m_proto = SCHEME_IPC;
-		else if (prototext == "device") m_proto = SCHEME_DEVICE;
-		else if (prototext == "file") m_proto = SCHEME_FILE;
-		else if (prototext == "group") m_proto = SCHEME_GROUP;
-		else m_proto = SCHEME_OTHER;
-		m_protostr = prototext;
-
-		std::string porttext = std::string(uri.portText.first, uri.portText.afterLast - uri.portText.first);
-		m_port = atoi(porttext.c_str());
-		m_userinfo = std::string(uri.userInfo.first, uri.userInfo.afterLast - uri.userInfo.first);
-
-		for (auto h=uri.pathHead; h!=NULL; h=h->next) {
-			auto pstr = std::string(
-					h->text.first, h->text.afterLast - h->text.first);
-
-			m_path += "/";
-			m_path += pstr;
-			m_pathseg.push_back(pstr);
-		}
-
-		//string query = std::string(uri.query.first, uri.query.afterLast - uri.query.first);
-		if (uri.query.afterLast - uri.query.first > 0) {
-			UriQueryListA *queryList;
-			int itemCount;
-			if (uriDissectQueryMallocA(&queryList, &itemCount, uri.query.first,
-					uri.query.afterLast) != URI_SUCCESS) {
-				// Failure
-			}
-
-			UriQueryListA *item = queryList;
-			while (item) {
-				m_qmap[item->key] = item->value;
-				item = item->next;
-			}
-			uriFreeQueryListA(queryList);
-		}
-
-		uriFreeUriMembersA(&uri);
-
-		auto fraglast = (uri.query.first != NULL) ? uri.query.first : uri.fragment.afterLast;
-		if (uri.fragment.first != NULL && fraglast - uri.fragment.first > 0) {
-			m_frag = std::string(uri.fragment.first, fraglast - uri.fragment.first);
-		}
-
-		m_valid = m_proto != SCHEME_NONE && (m_host.size() > 0 || m_path.size() > 0);
-
-		if (m_valid) {
-			// remove userinfo from base uri
-			const char *start = uri.scheme.first;
-			if (m_userinfo != "") {
-				m_base = std::string(start, uri.userInfo.first - start);
-				start = uri.userInfo.afterLast + 1;
-			}
-			else {
-				m_base = std::string("");
-			}
-			if (m_qmap.size() > 0) {
-				m_base += std::string(start, uri.query.first - start - 1);
-			}
-			else if (uri.fragment.first != NULL) {
-				m_base += std::string(start, uri.fragment.first - start - 1);
-			}
-			else if (start) {
-				m_base += std::string(start);
-			}
-			else {
-				m_base += std::string("");
-			}
-		}
-	}
+        m_valid = false;
+        m_host = "none";
+        m_port = -1;
+        m_proto = SCHEME_NONE;
+        m_base = suri;
+        m_path = "";
+        m_frag = "";
+    } else {
+        m_host = std::string(uri.hostText.first, uri.hostText.afterLast - uri.hostText.first);
+
+        std::string prototext = std::string(uri.scheme.first, uri.scheme.afterLast - uri.scheme.first);
+        if (prototext == "tcp") m_proto = SCHEME_TCP;
+        else if (prototext == "udp") m_proto = SCHEME_UDP;
+        else if (prototext == "ftl") m_proto = SCHEME_FTL;
+        else if (prototext == "http") m_proto = SCHEME_HTTP;
+        else if (prototext == "ws") m_proto = SCHEME_WS;
+        else if (prototext == "wss") m_proto = SCHEME_WSS;
+        else if (prototext == "ipc") m_proto = SCHEME_IPC;
+        else if (prototext == "device") m_proto = SCHEME_DEVICE;
+        else if (prototext == "file") m_proto = SCHEME_FILE;
+        else if (prototext == "group") m_proto = SCHEME_GROUP;
+        else
+            m_proto = SCHEME_OTHER;
+        m_protostr = prototext;
+
+        std::string porttext = std::string(uri.portText.first, uri.portText.afterLast - uri.portText.first);
+        m_port = atoi(porttext.c_str());
+        m_userinfo = std::string(uri.userInfo.first, uri.userInfo.afterLast - uri.userInfo.first);
+
+        for (auto h = uri.pathHead; h != NULL; h = h->next) {
+            auto pstr = std::string(
+                    h->text.first, h->text.afterLast - h->text.first);
+
+            m_path += "/";
+            m_path += pstr;
+            m_pathseg.push_back(pstr);
+        }
+
+        // string query = std::string(uri.query.first, uri.query.afterLast - uri.query.first);
+        if (uri.query.afterLast - uri.query.first > 0) {
+            UriQueryListA *queryList;
+            int itemCount;
+            if (uriDissectQueryMallocA(&queryList, &itemCount, uri.query.first,
+                    uri.query.afterLast) != URI_SUCCESS) {
+                // Failure
+            }
+
+            UriQueryListA *item = queryList;
+            while (item) {
+                m_qmap[item->key] = item->value;
+                item = item->next;
+            }
+            uriFreeQueryListA(queryList);
+        }
+
+        uriFreeUriMembersA(&uri);
+
+        auto fraglast = (uri.query.first != NULL) ? uri.query.first : uri.fragment.afterLast;
+        if (uri.fragment.first != NULL && fraglast - uri.fragment.first > 0) {
+            m_frag = std::string(uri.fragment.first, fraglast - uri.fragment.first);
+        }
+
+        m_valid = m_proto != SCHEME_NONE && (m_host.size() > 0 || m_path.size() > 0);
+
+        if (m_valid) {
+            // remove userinfo from base uri
+            const char *start = uri.scheme.first;
+            if (m_userinfo != "") {
+                m_base = std::string(start, uri.userInfo.first - start);
+                start = uri.userInfo.afterLast + 1;
+            } else {
+                m_base = std::string("");
+            }
+            if (m_qmap.size() > 0) {
+                m_base += std::string(start, uri.query.first - start - 1);
+            } else if (uri.fragment.first != NULL) {
+                m_base += std::string(start, uri.fragment.first - start - 1);
+            } else if (start) {
+                m_base += std::string(start);
+            } else {
+                m_base += std::string("");
+            }
+        }
+    }
 }
 
 string URI::to_string() const {
-	return (m_qmap.size() > 0) ? m_base + "?" + getQuery() : m_base;
+    return (m_qmap.size() > 0) ? m_base + "?" + getQuery() : m_base;
 }
 
 string URI::getPathSegment(int n) const {
-	size_t N = (n < 0) ? m_pathseg.size()+n : n;
-	if (N < 0 || N >= m_pathseg.size()) return "";
-	else return m_pathseg[N];
+    size_t N = (n < 0) ? m_pathseg.size()+n : n;
+    if (N < 0 || N >= m_pathseg.size()) return "";
+    else
+        return m_pathseg[N];
 }
 
 string URI::getBaseURI(int n) const {
-	if (n >= (int)m_pathseg.size()) return m_base;
-	if (n >= 0) {
-		string r = m_protostr + string("://") + m_host + ((m_port != 0) ? string(":") + std::to_string(m_port) : "");
-		for (int i=0; i<n; i++) {
-			r += "/";
-			r += getPathSegment(i);
-		}
-
-		return r;
-	} else if (m_pathseg.size()+n >= 0) {
-		string r = m_protostr + string("://") + m_host + ((m_port != 0) ? string(":") + std::to_string(m_port) : "");
-		size_t N = m_pathseg.size()+n;
-		for (size_t i=0; i<N; i++) {
-			r += "/";
-			r += getPathSegment(static_cast<int>(i));
-		}
-
-		return r;
-	} else return "";
+    if (n >= static_cast<int>(m_pathseg.size())) return m_base;
+    if (n >= 0) {
+        string r = m_protostr + string("://") + m_host + ((m_port != 0) ? string(":") + std::to_string(m_port) : "");
+        for (int i = 0; i < n; i++) {
+            r += "/";
+            r += getPathSegment(i);
+        }
+
+        return r;
+    } else if (m_pathseg.size()+n >= 0) {
+        string r = m_protostr + string("://") + m_host + ((m_port != 0) ? string(":") + std::to_string(m_port) : "");
+        size_t N = m_pathseg.size()+n;
+        for (size_t i = 0; i < N; i++) {
+            r += "/";
+            r += getPathSegment(static_cast<int>(i));
+        }
+
+        return r;
+    } else {
+        return "";
+    }
 }
 
 std::string URI::getBaseURIWithUser() const {
-	std::string result;
-
-	result += m_protostr + "://";
-	if (m_userinfo.size() > 0) {
-		result += getUserInfo();
-		result += "@";
-	}
-	result += m_host;
-	if (m_port > 0) result += std::string(":") + std::to_string(m_port);
-	result += m_path;
-	return result;
+    std::string result;
+
+    result += m_protostr + "://";
+    if (m_userinfo.size() > 0) {
+        result += getUserInfo();
+        result += "@";
+    }
+    result += m_host;
+    if (m_port > 0) result += std::string(":") + std::to_string(m_port);
+    result += m_path;
+    return result;
 }
 
 string URI::getQuery() const {
-	string q;
-	for (auto x : m_qmap) {
-		if (q.length() > 0) q += "&";
-		q += x.first + "=" + x.second;
-	}
-	return q;
-};
+    string q;
+    for (auto x : m_qmap) {
+        if (q.length() > 0) q += "&";
+        q += x.first + "=" + x.second;
+    }
+    return q;
+}
 
 void URI::setAttribute(const string &key, const string &value) {
-	m_qmap[key] = value;
+    m_qmap[key] = value;
 }
 
 void URI::setAttribute(const string &key, int value) {
-	m_qmap[key] = std::to_string(value);
+    m_qmap[key] = std::to_string(value);
 }
 
 void URI::to_json(nlohmann::json &json) const {
-	std::string uri = to_string();
-	if (m_frag.size() > 0) uri += std::string("#") + getFragment();
-
-	json["uri"] = uri;
-	for (auto i : m_qmap) {
-		auto *current = &json;
-
-		size_t pos = 0;
-		size_t lpos = 0;
-		while ((pos = i.first.find('/', lpos)) != std::string::npos) {
-			std::string subobj = i.first.substr(lpos, pos-lpos);
-			current = &((*current)[subobj]);
-			lpos = pos+1;
-		}
-
-		std::string obj = i.first.substr(lpos);
-
-		auto p = nlohmann::json::parse(i.second, nullptr, false);
-		if (!p.is_discarded()) {
-			(*current)[obj] = p;
-		} else {
-			(*current)[obj] = i.second;
-		}
-	}
+    std::string uri = to_string();
+    if (m_frag.size() > 0) uri += std::string("#") + getFragment();
+
+    json["uri"] = uri;
+    for (auto i : m_qmap) {
+        auto *current = &json;
+
+        size_t pos = 0;
+        size_t lpos = 0;
+        while ((pos = i.first.find('/', lpos)) != std::string::npos) {
+            std::string subobj = i.first.substr(lpos, pos-lpos);
+            current = &((*current)[subobj]);
+            lpos = pos+1;
+        }
+
+        std::string obj = i.first.substr(lpos);
+
+        auto p = nlohmann::json::parse(i.second, nullptr, false);
+        if (!p.is_discarded()) {
+            (*current)[obj] = p;
+        } else {
+            (*current)[obj] = i.second;
+        }
+    }
 }
 
 bool URI::hasUserInfo() const {
-	return m_userinfo != "";
+    return m_userinfo != "";
 }
 
 const std::string &URI::getUserInfo() const {
-	return m_userinfo;
+    return m_userinfo;
 }
diff --git a/test/broadcast_unit.cpp b/test/broadcast_unit.cpp
index 77a587e1f1df1e1067791c6e06ebb5128d425828..56f012eed2394648dcc6f318933e13815309832e 100644
--- a/test/broadcast_unit.cpp
+++ b/test/broadcast_unit.cpp
@@ -15,66 +15,66 @@ using ftl::protocol::ChannelSet;
 using ftl::protocol::FrameID;
 
 class BTestStream : public ftl::protocol::Stream {
-	public:
-	BTestStream() {};
-	~BTestStream() {};
-
-	bool post(const ftl::protocol::StreamPacket &spkt, const ftl::protocol::Packet &pkt) {
-		seen(FrameID(spkt.streamID, spkt.frame_number), spkt.channel);
-		trigger(spkt, pkt);
-		return true;
-	}
+    public:
+    BTestStream() {};
+    ~BTestStream() {};
+
+    bool post(const ftl::protocol::StreamPacket &spkt, const ftl::protocol::Packet &pkt) {
+        seen(FrameID(spkt.streamID, spkt.frame_number), spkt.channel);
+        trigger(spkt, pkt);
+        return true;
+    }
 
-	bool begin() override { return true; }
-	bool end() override { return true; }
-	bool active() override { return true; }
+    bool begin() override { return true; }
+    bool end() override { return true; }
+    bool active() override { return true; }
 
-	void setProperty(ftl::protocol::StreamProperty opt, std::any value) override {}
+    void setProperty(ftl::protocol::StreamProperty opt, std::any value) override {}
 
-	std::any getProperty(ftl::protocol::StreamProperty opt) override { return 0; }
+    std::any getProperty(ftl::protocol::StreamProperty opt) override { return 0; }
 
-	bool supportsProperty(ftl::protocol::StreamProperty opt) override { return true; }
+    bool supportsProperty(ftl::protocol::StreamProperty opt) override { return true; }
 
-	void forceSeen(FrameID id, Channel channel) {
+    void forceSeen(FrameID id, Channel channel) {
         seen(id, channel);
     }
 };
 
 TEST_CASE("ftl::stream::Broadcast()::write", "[stream]") {
-	std::unique_ptr<Broadcast> mux = std::make_unique<Broadcast>();
-	REQUIRE(mux);
-
-	SECTION("write with two streams") {
-		std::shared_ptr<Stream> s1 = std::make_shared<BTestStream>();
-		REQUIRE(s1);
-		std::shared_ptr<Stream> s2 = std::make_shared<BTestStream>();
-		REQUIRE(s2);
-
-		mux->add(s1);
-		mux->add(s2);
-
-		StreamPacket tspkt1 = {4,0,0,1,Channel::kColour};
-		StreamPacket tspkt2 = {4,0,0,1,Channel::kColour};
-
-		auto h1 = s1->onPacket([&tspkt1](const StreamPacket &spkt, const Packet &pkt) {
-			tspkt1 = spkt;
-			return true;
-		});
-		auto h2 = s2->onPacket([&tspkt2](const StreamPacket &spkt, const Packet &pkt) {
-			tspkt2 = spkt;
-			return true;
-		});
-
-		REQUIRE( mux->post({4,100,0,1,Channel::kColour},{}) );
-		REQUIRE( tspkt1.timestamp == 100 );
-		REQUIRE( tspkt2.timestamp == 100 );
-	}
+    std::unique_ptr<Broadcast> mux = std::make_unique<Broadcast>();
+    REQUIRE(mux);
+
+    SECTION("write with two streams") {
+        std::shared_ptr<Stream> s1 = std::make_shared<BTestStream>();
+        REQUIRE(s1);
+        std::shared_ptr<Stream> s2 = std::make_shared<BTestStream>();
+        REQUIRE(s2);
+
+        mux->add(s1);
+        mux->add(s2);
+
+        StreamPacket tspkt1 = {4,0,0,1,Channel::kColour};
+        StreamPacket tspkt2 = {4,0,0,1,Channel::kColour};
+
+        auto h1 = s1->onPacket([&tspkt1](const StreamPacket &spkt, const Packet &pkt) {
+            tspkt1 = spkt;
+            return true;
+        });
+        auto h2 = s2->onPacket([&tspkt2](const StreamPacket &spkt, const Packet &pkt) {
+            tspkt2 = spkt;
+            return true;
+        });
+
+        REQUIRE( mux->post({4,100,0,1,Channel::kColour},{}) );
+        REQUIRE( tspkt1.timestamp == 100 );
+        REQUIRE( tspkt2.timestamp == 100 );
+    }
 
 }
 
 TEST_CASE("Broadcast enable", "[stream]") {
-	std::unique_ptr<Broadcast> mux = std::make_unique<Broadcast>();
-	REQUIRE(mux);
+    std::unique_ptr<Broadcast> mux = std::make_unique<Broadcast>();
+    REQUIRE(mux);
 
     std::shared_ptr<BTestStream> s1 = std::make_shared<BTestStream>();
     REQUIRE(s1);
@@ -82,12 +82,12 @@ TEST_CASE("Broadcast enable", "[stream]") {
     REQUIRE(s2);
 
     mux->add(s1);
-	mux->add(s2);
+    mux->add(s2);
 
     SECTION("enable frame id") {
         FrameID id1(0, 1);
         s1->forceSeen(id1, Channel::kColour);
-		// s2->forceSeen(id1, Channel::kColour);
+        // s2->forceSeen(id1, Channel::kColour);
 
         REQUIRE( !s1->enabled(id1) );
         REQUIRE( mux->enable(id1) );
@@ -111,15 +111,15 @@ TEST_CASE("Broadcast enable", "[stream]") {
     SECTION("enable frame id for unseen") {
         FrameID id(0, 1);
         REQUIRE( mux->enable(id) );
-		REQUIRE( s1->enabled(id) );
-		REQUIRE( s2->enabled(id) );
+        REQUIRE( s1->enabled(id) );
+        REQUIRE( s2->enabled(id) );
     }
 
     SECTION("enable channel for unseen") {
         FrameID id(0, 1);
         REQUIRE( mux->enable(id, Channel::kDepth) );
-		REQUIRE( s1->enabled(id, Channel::kDepth) );
-		REQUIRE( s2->enabled(id, Channel::kDepth) );
+        REQUIRE( s1->enabled(id, Channel::kDepth) );
+        REQUIRE( s2->enabled(id, Channel::kDepth) );
     }
 
     SECTION("enable channel set for unseen") {
diff --git a/test/peer_unit.cpp b/test/peer_unit.cpp
index 219f47c7ccfa0173e2ae28ceabe716f9dd4a5b5c..3679e6d7b954d014e4eaa9b845c20389fa01f5c9 100644
--- a/test/peer_unit.cpp
+++ b/test/peer_unit.cpp
@@ -34,302 +34,302 @@ static std::atomic<int> ctr_ = 0;
 // --- Tests -------------------------------------------------------------------
 
 TEST_CASE("Peer(int)", "[]") {
-	SECTION("initiates a valid handshake") {
-		auto s = createMockPeer(ctr_++);
-		s->start();
+    SECTION("initiates a valid handshake") {
+        auto s = createMockPeer(ctr_++);
+        s->start();
 
-		LOG(INFO) << "STARTED";
+        LOG(INFO) << "STARTED";
 
-		auto [name, hs] = readResponse<ftl::net::Handshake>(0);
-		
-		REQUIRE( name == "__handshake__" );
-		
-		// 1) Sends magic (64bits)
-		REQUIRE( get<0>(hs) == ftl::net::kMagic );
-		 
-		// 2) Sends FTL Version
-		REQUIRE( get<1>(hs) == (FTL_VERSION_MAJOR << 16) + (FTL_VERSION_MINOR << 8) + FTL_VERSION_PATCH );
-		
-		// 3) Sends peer UUID
-		
-		
-		REQUIRE( s->status() == NodeStatus::kConnecting );
-	}
-	
-	SECTION("completes on full handshake") {
-		int lidx = ctr_++;
-		int cidx = ctr_++;
-		auto s_l = createMockPeer(lidx);
-		auto s_c = createMockPeer(cidx);
+        auto [name, hs] = readResponse<ftl::net::Handshake>(0);
+        
+        REQUIRE( name == "__handshake__" );
+        
+        // 1) Sends magic (64bits)
+        REQUIRE( get<0>(hs) == ftl::net::kMagic );
+         
+        // 2) Sends FTL Version
+        REQUIRE( get<1>(hs) == static_cast<unsigned int>((FTL_VERSION_MAJOR << 16) + (FTL_VERSION_MINOR << 8) + FTL_VERSION_PATCH ));
+        
+        // 3) Sends peer UUID
+        
+        
+        REQUIRE( s->status() == NodeStatus::kConnecting );
+    }
+    
+    SECTION("completes on full handshake") {
+        int lidx = ctr_++;
+        int cidx = ctr_++;
+        auto s_l = createMockPeer(lidx);
+        auto s_c = createMockPeer(cidx);
 
-		s_l->start();
-		
-		// get sent message by s_l and place it in s_c's buffer
-		fakedata[cidx] = fakedata[lidx]; 
-		s_l->data(); // listenin peer: process
-		// vice versa, listening peer gets reply and processes it
-		fakedata[lidx] = fakedata[cidx]; 
-		s_c->data(); // connecting peer: process
-		sleep_for(milliseconds(50));
+        s_l->start();
+        
+        // get sent message by s_l and place it in s_c's buffer
+        fakedata[cidx] = fakedata[lidx]; 
+        s_l->data(); // listenin peer: process
+        // vice versa, listening peer gets reply and processes it
+        fakedata[lidx] = fakedata[cidx]; 
+        s_c->data(); // connecting peer: process
+        sleep_for(milliseconds(50));
 
-		// both peers should be connected now
-		REQUIRE( s_c->status() == NodeStatus::kConnected );
-		REQUIRE( s_l->status() == NodeStatus::kConnected );
-	}
-	
-	SECTION("has correct version on full handshake") {
-		
-		// MockPeer s = MockPeer::create_connecting_peer();
-		// Send handshake response
-		// send_handshake(s);
-		// s.mock_data();
-		//sleep_for(milliseconds(50));
-		// REQUIRE( (s.getFTLVersion() ==  (8 << 16) + (5 << 8) + 2) );
-	}
-	
-	SECTION("has correct peer id on full handshake") {
-		// MockPeer s = MockPeer::create_connecting_peer();
-		//
-		// Send handshake response
-		//REQUIRE( s.id() ==   );
-	}
+        // both peers should be connected now
+        REQUIRE( s_c->status() == NodeStatus::kConnected );
+        REQUIRE( s_l->status() == NodeStatus::kConnected );
+    }
+    
+    SECTION("has correct version on full handshake") {
+        
+        // MockPeer s = MockPeer::create_connecting_peer();
+        // Send handshake response
+        // send_handshake(s);
+        // s.mock_data();
+        //sleep_for(milliseconds(50));
+        // REQUIRE( (s.getFTLVersion() ==  (8 << 16) + (5 << 8) + 2) );
+    }
+    
+    SECTION("has correct peer id on full handshake") {
+        // MockPeer s = MockPeer::create_connecting_peer();
+        //
+        // Send handshake response
+        //REQUIRE( s.id() ==   );
+    }
 
-	ftl::protocol::reset();
+    ftl::protocol::reset();
 }
 
 TEST_CASE("Peer::call()", "[rpc]") {
-	int c = ctr_++;
-	auto s = createMockPeer(c);
-	send_handshake(*s.get());
-	s->data();
-	sleep_for(milliseconds(50));
-	
-	SECTION("one argument call") {
-		REQUIRE( s->isConnected() );
-		
-		fakedata[c] = "";
-		
-		// Thread to provide response to otherwise blocking call
-		std::thread thr([&s, c]() {
-			while (fakedata[c].size() == 0) std::this_thread::sleep_for(std::chrono::milliseconds(20));
-			
-			auto [id,value] = readRPC<tuple<int>>(c);
-			auto res_obj = std::make_tuple(1,id,"__return__",get<0>(value)+22);
-			std::stringstream buf;
-			msgpack::pack(buf, res_obj);
-			fakedata[c] = buf.str();
-			s->data();
-			sleep_for(milliseconds(50));
-		});
-		int res = s->call<int>("test1", 44);
-		thr.join();
-		
-		REQUIRE( (res == 66) );
-	}
-	
-	SECTION("no argument call") {
-		REQUIRE( s->isConnected() );
-		
-		fakedata[c] = "";
-		
-		// Thread to provide response to otherwise blocking call
-		std::thread thr([&s, c]() {
-			while (fakedata[c].size() == 0) std::this_thread::sleep_for(std::chrono::milliseconds(20));
-			
-			auto res = readRPC<tuple<>>(c);
-			auto res_obj = std::make_tuple(1,std::get<0>(res),"__return__",77);
-			std::stringstream buf;
-			msgpack::pack(buf, res_obj);
-			fakedata[c] = buf.str();
-			s->data();
-			sleep_for(milliseconds(50));
-		});
-		
-		int res = s->call<int>("test1");
-		
-		thr.join();
-		
-		REQUIRE( (res == 77) );
-	}
+    int c = ctr_++;
+    auto s = createMockPeer(c);
+    send_handshake(*s.get());
+    s->data();
+    sleep_for(milliseconds(50));
+    
+    SECTION("one argument call") {
+        REQUIRE( s->isConnected() );
+        
+        fakedata[c] = "";
+        
+        // Thread to provide response to otherwise blocking call
+        std::thread thr([&s, c]() {
+            while (fakedata[c].size() == 0) std::this_thread::sleep_for(std::chrono::milliseconds(20));
+            
+            auto [id,value] = readRPC<tuple<int>>(c);
+            auto res_obj = std::make_tuple(1,id,"__return__",get<0>(value)+22);
+            std::stringstream buf;
+            msgpack::pack(buf, res_obj);
+            fakedata[c] = buf.str();
+            s->data();
+            sleep_for(milliseconds(50));
+        });
+        int res = s->call<int>("test1", 44);
+        thr.join();
+        
+        REQUIRE( (res == 66) );
+    }
+    
+    SECTION("no argument call") {
+        REQUIRE( s->isConnected() );
+        
+        fakedata[c] = "";
+        
+        // Thread to provide response to otherwise blocking call
+        std::thread thr([&s, c]() {
+            while (fakedata[c].size() == 0) std::this_thread::sleep_for(std::chrono::milliseconds(20));
+            
+            auto res = readRPC<tuple<>>(c);
+            auto res_obj = std::make_tuple(1,std::get<0>(res),"__return__",77);
+            std::stringstream buf;
+            msgpack::pack(buf, res_obj);
+            fakedata[c] = buf.str();
+            s->data();
+            sleep_for(milliseconds(50));
+        });
+        
+        int res = s->call<int>("test1");
+        
+        thr.join();
+        
+        REQUIRE( (res == 77) );
+    }
 
-	SECTION("vector return from call") {
-		REQUIRE( s->isConnected() );
-		
-		fakedata[c] = "";
-		
-		// Thread to provide response to otherwise blocking call
-		std::thread thr([&s, c]() {
-			while (fakedata[c].size() == 0) std::this_thread::sleep_for(std::chrono::milliseconds(20));
-			
-			auto res = readRPC<tuple<>>(c);
-			vector<int> data = {44,55,66};
-			auto res_obj = std::make_tuple(1,std::get<0>(res),"__return__",data);
-			std::stringstream buf;
-			msgpack::pack(buf, res_obj);
-			fakedata[c] = buf.str();
-			s->data();
-			sleep_for(milliseconds(50));
-		});
-		
-		vector<int> res = s->call<vector<int>>("test1");
-		
-		thr.join();
-		
-		REQUIRE( (res[0] == 44) );
-		REQUIRE( (res[2] == 66) );
-	}
+    SECTION("vector return from call") {
+        REQUIRE( s->isConnected() );
+        
+        fakedata[c] = "";
+        
+        // Thread to provide response to otherwise blocking call
+        std::thread thr([&s, c]() {
+            while (fakedata[c].size() == 0) std::this_thread::sleep_for(std::chrono::milliseconds(20));
+            
+            auto res = readRPC<tuple<>>(c);
+            vector<int> data = {44,55,66};
+            auto res_obj = std::make_tuple(1,std::get<0>(res),"__return__",data);
+            std::stringstream buf;
+            msgpack::pack(buf, res_obj);
+            fakedata[c] = buf.str();
+            s->data();
+            sleep_for(milliseconds(50));
+        });
+        
+        vector<int> res = s->call<vector<int>>("test1");
+        
+        thr.join();
+        
+        REQUIRE( (res[0] == 44) );
+        REQUIRE( (res[2] == 66) );
+    }
 
-	s.reset();
-	ftl::protocol::reset();
+    s.reset();
+    ftl::protocol::reset();
 }
 
 TEST_CASE("Peer::bind()", "[rpc]") {
-	int c = ctr_++;
-	auto s = createMockPeer(c);
-	send_handshake(*s.get());
-	s->data();
-	sleep_for(milliseconds(50));
-	
+    int c = ctr_++;
+    auto s = createMockPeer(c);
+    send_handshake(*s.get());
+    s->data();
+    sleep_for(milliseconds(50));
+    
 
-	SECTION("no argument call") {
-		bool done = false;
-		
-		s->bind("hello", [&]() {
-			done = true;
-		});
+    SECTION("no argument call") {
+        bool done = false;
+        
+        s->bind("hello", [&]() {
+            done = true;
+        });
 
-		s->send("hello");
-		s->data(); // Force it to read the fake send...
-		sleep_for(milliseconds(50));
-		
-		REQUIRE( done );
-	}
-	
-	SECTION("one argument call") {		
-		int done = 0;
-		
-		s->bind("hello", [&](int a) {
-			done = a;
-		});
-		
-		s->send("hello", 55);
-		s->data(); // Force it to read the fake send...
-		sleep_for(milliseconds(50));
-		
-		REQUIRE( (done == 55) );
-	}
-	
-	SECTION("two argument call") {		
-		std::string done;
-		
-		s->bind("hello", [&](int a, const std::string &b) {
-			done = b;
-		});
+        s->send("hello");
+        s->data(); // Force it to read the fake send...
+        sleep_for(milliseconds(50));
+        
+        REQUIRE( done );
+    }
+    
+    SECTION("one argument call") {		
+        int done = 0;
+        
+        s->bind("hello", [&](int a) {
+            done = a;
+        });
+        
+        s->send("hello", 55);
+        s->data(); // Force it to read the fake send...
+        sleep_for(milliseconds(50));
+        
+        REQUIRE( (done == 55) );
+    }
+    
+    SECTION("two argument call") {		
+        std::string done;
+        
+        s->bind("hello", [&](int a, const std::string &b) {
+            done = b;
+        });
 
-		s->send("hello", 55, "world");
-		s->data(); // Force it to read the fake send...
-		sleep_for(milliseconds(50));
-		
-		REQUIRE( (done == "world") );
-	}
+        s->send("hello", 55, "world");
+        s->data(); // Force it to read the fake send...
+        sleep_for(milliseconds(50));
+        
+        REQUIRE( (done == "world") );
+    }
 
-	SECTION("int return value") {		
-		int done = 0;
-		
-		s->bind("hello", [&](int a) -> int {
-			done = a;
-			return a;
-		});
-		
-		s->asyncCall<int>("hello", [](int a){}, 55);
-		s->data(); // Force it to read the fake send...
-		sleep_for(milliseconds(50));
-		
-		REQUIRE( (done == 55) );
-		REQUIRE( (readRPCReturn<int>(c) == 55) );
-	}
+    SECTION("int return value") {		
+        int done = 0;
+        
+        s->bind("hello", [&](int a) -> int {
+            done = a;
+            return a;
+        });
+        
+        s->asyncCall<int>("hello", [](int a){}, 55);
+        s->data(); // Force it to read the fake send...
+        sleep_for(milliseconds(50));
+        
+        REQUIRE( (done == 55) );
+        REQUIRE( (readRPCReturn<int>(c) == 55) );
+    }
 
-	SECTION("vector return value") {		
-		int done = 0;
-		
-		s->bind("hello", [&](int a) -> vector<int> {
-			done = a;
-			vector<int> b = {a,45};
-			return b;
-		});
-		
-		s->asyncCall<int>("hello", [](int a){}, 55);
-		s->data(); // Force it to read the fake send...
-		sleep_for(milliseconds(50));
-		
-		REQUIRE( (done == 55) );
+    SECTION("vector return value") {		
+        int done = 0;
+        
+        s->bind("hello", [&](int a) -> vector<int> {
+            done = a;
+            vector<int> b = {a,45};
+            return b;
+        });
+        
+        s->asyncCall<int>("hello", [](int a){}, 55);
+        s->data(); // Force it to read the fake send...
+        sleep_for(milliseconds(50));
+        
+        REQUIRE( (done == 55) );
 
-		auto res = readRPCReturn<vector<int>>(c);
-		REQUIRE( (res[1] == 45) );
-	}
+        auto res = readRPCReturn<vector<int>>(c);
+        REQUIRE( (res[1] == 45) );
+    }
 
-	s.reset();
-	ftl::protocol::reset();
+    s.reset();
+    ftl::protocol::reset();
 }
 
 TEST_CASE("Socket::send()", "[io]") {
-	int c = ctr_++;
-	auto s = createMockPeer(c);
-	sleep_for(milliseconds(50));
+    int c = ctr_++;
+    auto s = createMockPeer(c);
+    sleep_for(milliseconds(50));
 
-	SECTION("send an int") {
-		int i = 607;
-		
-		s->send("dummy",i);
-		
-		auto [name, value] = readResponse<tuple<int>>(c);
-		
-		REQUIRE( (name == "dummy") );
-		REQUIRE( (get<0>(value) == 607) );
-	}
-	
-	SECTION("send a string") {
-		std::string str("hello world");
-		s->send("dummy",str);
-		
-		auto [name, value] = readResponse<tuple<std::string>>(c);
-		
-		REQUIRE( (name == "dummy") );
-		REQUIRE( (get<0>(value) == "hello world") );
-	}
-	
-	SECTION("send const char* string") {
-		s->send("dummy","hello world");
-		
-		auto [name, value] = readResponse<tuple<std::string>>(c);
-		
-		REQUIRE( (name == "dummy") );
-		REQUIRE( (get<0>(value) == "hello world") );
-	}
-	
-	SECTION("send a tuple") {
-		auto tup = std::make_tuple(55,66,true,6.7);
-		s->send("dummy",tup);
-		
-		auto [name, value] = readResponse<tuple<decltype(tup)>>(c);
-		
-		REQUIRE( (name == "dummy") );
-		REQUIRE( (get<1>(get<0>(value)) == 66) );
-	}
-	
-	SECTION("send multiple strings") {
-		std::string str("hello ");
-		std::string str2("world");
-		s->send("dummy2",str,str2);
-		
-		auto [name, value] = readResponse<tuple<std::string,std::string>>(c);
-		
-		REQUIRE( (name == "dummy2") );
-		REQUIRE( (get<0>(value) == "hello ") );
-		REQUIRE( (get<1>(value) == "world") );
-	}
+    SECTION("send an int") {
+        int i = 607;
+        
+        s->send("dummy",i);
+        
+        auto [name, value] = readResponse<tuple<int>>(c);
+        
+        REQUIRE( (name == "dummy") );
+        REQUIRE( (get<0>(value) == 607) );
+    }
+    
+    SECTION("send a string") {
+        std::string str("hello world");
+        s->send("dummy",str);
+        
+        auto [name, value] = readResponse<tuple<std::string>>(c);
+        
+        REQUIRE( (name == "dummy") );
+        REQUIRE( (get<0>(value) == "hello world") );
+    }
+    
+    SECTION("send const char* string") {
+        s->send("dummy","hello world");
+        
+        auto [name, value] = readResponse<tuple<std::string>>(c);
+        
+        REQUIRE( (name == "dummy") );
+        REQUIRE( (get<0>(value) == "hello world") );
+    }
+    
+    SECTION("send a tuple") {
+        auto tup = std::make_tuple(55,66,true,6.7);
+        s->send("dummy",tup);
+        
+        auto [name, value] = readResponse<tuple<decltype(tup)>>(c);
+        
+        REQUIRE( (name == "dummy") );
+        REQUIRE( (get<1>(get<0>(value)) == 66) );
+    }
+    
+    SECTION("send multiple strings") {
+        std::string str("hello ");
+        std::string str2("world");
+        s->send("dummy2",str,str2);
+        
+        auto [name, value] = readResponse<tuple<std::string,std::string>>(c);
+        
+        REQUIRE( (name == "dummy2") );
+        REQUIRE( (get<0>(value) == "hello ") );
+        REQUIRE( (get<1>(value) == "world") );
+    }
 
-	s.reset();
-	ftl::protocol::reset();
+    s.reset();
+    ftl::protocol::reset();
 }