changeset 83:d458af0b7748

Server: namespace and hierarchy
author David Demelier <markand@malikania.fr>
date Sun, 22 Jan 2017 17:54:56 +0100
parents ee850a6ab89e
children bb859ba34ce4
files database/sqlite/src/account.cpp libserver/CMakeLists.txt libserver/malikania/account.hpp libserver/malikania/account_dao.cpp libserver/malikania/account_dao.hpp libserver/malikania/client.cpp libserver/malikania/client.hpp libserver/malikania/database.cpp libserver/malikania/database.hpp libserver/malikania/hash.hpp libserver/malikania/server.cpp libserver/malikania/server.hpp libserver/malikania/server/account.hpp libserver/malikania/server/account_dao.cpp libserver/malikania/server/account_dao.hpp libserver/malikania/server/client.cpp libserver/malikania/server/client.hpp libserver/malikania/server/database.cpp libserver/malikania/server/database.hpp libserver/malikania/server/hash.hpp libserver/malikania/server/server.cpp libserver/malikania/server/server.hpp server/main.cpp
diffstat 23 files changed, 1208 insertions(+), 1171 deletions(-) [+]
line wrap: on
line diff
--- a/database/sqlite/src/account.cpp	Sun Jan 22 11:07:36 2017 +0100
+++ b/database/sqlite/src/account.cpp	Sun Jan 22 17:54:56 2017 +0100
@@ -21,11 +21,12 @@
 
 #include <vector>
 
-#include <malikania/account.hpp>
+#include <malikania/server/account.hpp>
 
 #include "driver.hpp"
 
 using namespace mlk;
+using namespace mlk::server;
 
 namespace {
 
--- a/libserver/CMakeLists.txt	Sun Jan 22 11:07:36 2017 +0100
+++ b/libserver/CMakeLists.txt	Sun Jan 22 17:54:56 2017 +0100
@@ -20,19 +20,19 @@
 
 set(
     HEADERS
-    ${libmlk-server_SOURCE_DIR}/malikania/account.hpp
-    ${libmlk-server_SOURCE_DIR}/malikania/account_dao.hpp
-    ${libmlk-server_SOURCE_DIR}/malikania/client.hpp
-    ${libmlk-server_SOURCE_DIR}/malikania/database.hpp
-    ${libmlk-server_SOURCE_DIR}/malikania/server.hpp
+    ${libmlk-server_SOURCE_DIR}/malikania/server/account.hpp
+    ${libmlk-server_SOURCE_DIR}/malikania/server/account_dao.hpp
+    ${libmlk-server_SOURCE_DIR}/malikania/server/client.hpp
+    ${libmlk-server_SOURCE_DIR}/malikania/server/database.hpp
+    ${libmlk-server_SOURCE_DIR}/malikania/server/server.hpp
 )
 
 set(
     SOURCES
-    ${libmlk-server_SOURCE_DIR}/malikania/account_dao.cpp
-    ${libmlk-server_SOURCE_DIR}/malikania/client.cpp
-    ${libmlk-server_SOURCE_DIR}/malikania/database.cpp
-    ${libmlk-server_SOURCE_DIR}/malikania/server.cpp
+    ${libmlk-server_SOURCE_DIR}/malikania/server/account_dao.cpp
+    ${libmlk-server_SOURCE_DIR}/malikania/server/client.cpp
+    ${libmlk-server_SOURCE_DIR}/malikania/server/database.cpp
+    ${libmlk-server_SOURCE_DIR}/malikania/server/server.cpp
 )
 
 malikania_define_library(
--- a/libserver/malikania/account.hpp	Sun Jan 22 11:07:36 2017 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
- * account.hpp -- account model
- *
- * Copyright (c) 2013-2017 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MALIKANIA_ACCOUNT_HPP
-#define MALIKANIA_ACCOUNT_HPP
-
-/**
- * \file account.hpp
- * \brief Account model.
- */
-
-#include <cstdint>
-#include <string>
-
-namespace mlk {
-
-/**
- * \brief Account model
- */
-class account {
-public:
-    std::uint64_t id;
-    std::string name;
-    std::string email;
-    std::string first_name;
-    std::string last_name;
-    std::string password;
-};
-
-inline bool operator==(const account &ac1, const account &ac2) noexcept
-{
-    return ac1.id == ac2.id;
-}
-
-inline bool operator!=(const account &ac1, const account &ac2) noexcept
-{
-    return !(ac1 == ac2);
-}
-
-} // !mlk
-
-#endif // !MALIKANIA_ACCOUNT_HPP
--- a/libserver/malikania/account_dao.cpp	Sun Jan 22 11:07:36 2017 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +0,0 @@
-/*
- * dao-account.cpp -- database account management
- *
- * Copyright (c) 2013-2017 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "account.hpp"
-#include "account_dao.hpp"
-#include "database.hpp"
-#include "hash.hpp"
-
-namespace mlk {
-
-using create_func = void (account&);
-using remove_func = void (const account&);
-using update_func = void (account&);
-using get_func = boost::optional<account> (std::uint64_t);
-using find_by_name_func = boost::optional<account> (const std::string&);
-using list_func = std::vector<account> ();
-using count_func = std::uint64_t ();
-using clear_func = void ();
-
-bool account_dao::authenticate(const std::string& login, const std::string& pass)
-{
-    auto ac = find_by_name(login);
-    auto sha512 = hash::sha512(pass);
-
-    return ac && ac->password == sha512;
-}
-
-void account_dao::create(account& account)
-{
-    m_database.handle().get<create_func>("malikania_account_create")(account);
-}
-
-void account_dao::remove(const account& account)
-{
-    m_database.handle().get<remove_func>("malikania_account_remove")(account);
-}
-
-void account_dao::update(account& account)
-{
-    m_database.handle().get<update_func>("malikania_account_update")(account);
-}
-
-boost::optional<account> account_dao::get(uint64_t id)
-{
-    return m_database.handle().get<get_func>("malikania_account_get")(id);
-}
-
-boost::optional<account> account_dao::find_by_name(const std::string& name)
-{
-    return m_database.handle().get<find_by_name_func>("malikania_account_find_by_name")(name);
-}
-
-std::vector<account> account_dao::list()
-{
-    return m_database.handle().get<list_func>("malikania_account_list")();
-}
-
-std::uint64_t account_dao::count()
-{
-    return m_database.handle().get<count_func>("malikania_account_count")();
-}
-
-void account_dao::clear()
-{
-    m_database.handle().get<clear_func>("malikania_account_clear")();
-}
-
-} // !mlk
--- a/libserver/malikania/account_dao.hpp	Sun Jan 22 11:07:36 2017 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,135 +0,0 @@
-/*
- * account_dao.hpp -- database account management
- *
- * Copyright (c) 2013-2017 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MALIKANIA_SERVER_ACCOUNT_DAO_HPP
-#define MALIKANIA_SERVER_ACCOUNT_DAO_HPP
-
-/**
- * \file account_dao.hpp
- * \brief Database account management.
- */
-
-#include <cstdint>
-#include <vector>
-
-#include <boost/optional.hpp>
-
-namespace mlk {
-
-class database;
-class account;
-
-/**
- * \brief Account DAO.
- */
-class account_dao {
-private:
-    database& m_database;
-
-public:
-    /**
-     * Constructor.
-     *
-     * \param database the database
-     */
-    inline account_dao(database& database) noexcept
-        : m_database(database)
-    {
-    }
-
-    /**
-     * Check if the user authentication is valid.
-     *
-     * \param login the login name
-     * \param pass the clear password
-     * \return true if authentication was successful
-     */
-    bool authenticate(const std::string& login, const std::string& pass);
-
-    /**
-     * Create the given account.
-     *
-     * The object will be modified in place.
-     *
-     * \param account the account to add
-     * \throw std::exception on errors
-     */
-    void create(account& account);
-
-    /**
-     * Remove the given account, all data that references this account is
-     * deleted too.
-     *
-     * \param account the account
-     * \throw std::exception on errors
-     */
-    void remove(const account& account);
-
-    /**
-     * Update account only, does not recurse into objects that references the
-     * account.
-     *
-     * \param account the account
-     * \throw std::exception on errors
-     */
-    void update(account& account);
-
-    /**
-     * Get an account.
-     *
-     * \param id the account id
-     * \return the account
-     * \throw std::exception if not found
-     */
-    boost::optional<account> get(std::uint64_t id);
-
-    /**
-     * Find an account by name.
-     *
-     * \param name the account name
-     * \return the account or empty one if not found
-     * \throw std::exception on other errors
-     */
-    boost::optional<account> find_by_name(const std::string& name);
-
-    /**
-     * Get the list of account.
-     *
-     * \throw std::exception on errors
-     */
-    std::vector<account> list();
-
-    /**
-     * Get the number of accounts.
-     *
-     * \return the number of account.
-     */
-    std::uint64_t count();
-
-    /**
-     * Remove all accounts recursively.
-     *
-     * \throw std::exception on errors
-     * \warning use with care
-     */
-    void clear();
-};
-
-} // !mlk
-
-#endif // !MALIKANIA_SERVER_ACCOUNT_DAO_HPP
--- a/libserver/malikania/client.cpp	Sun Jan 22 11:07:36 2017 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,157 +0,0 @@
-#include <cassert>
-#include <iostream>
-
-#include "client.hpp"
-#include "server.hpp"
-
-namespace mlk {
-
-/*
- * client_proxy_writer
- * ------------------------------------------------------------------
- */
-
-client_proxy_writer::client_proxy_writer(std::shared_ptr<client> client, std::string init)
-    : m_client(std::move(client))
-{
-    assert(m_client);
-
-    m_output << init;
-}
-
-client_proxy_writer::~client_proxy_writer()
-{
-    m_client->send(m_output.str());
-}
-
-/*
- * client_proxy_writer
- * ------------------------------------------------------------------
- */
-
-void client::handle_read(boost::system::error_code code, std::size_t xfer)
-{
-    // TODO: use fixed size stream + verify exceed.
-    if (code) {
-        m_server.handle_disconnect(shared_from_this());
-    } else {
-        std::istringstream iss(std::string(
-            boost::asio::buffers_begin(m_input.data()),
-            boost::asio::buffers_begin(m_input.data()) + xfer - 4
-        ));
-
-        // Remove early in case of errors.
-        m_input.consume(xfer);
-
-        // Extract command name.
-        std::string cmd;
-        iss >> cmd >> std::ws;
-
-        if (!iss) {
-            return;
-        }
-
-        // Rest of the data.
-        std::string data(std::istreambuf_iterator<char>(iss), {});
-
-        if (!iss) {
-            return;
-        }
-
-        m_server.handle_message(shared_from_this(), std::move(cmd), std::move(data));
-        do_read();
-    }
-}
-
-void client::handle_write(boost::system::error_code code, std::size_t)
-{
-    if (code) {
-        m_server.handle_disconnect(shared_from_this());
-    } else {
-        m_output.pop_front();
-
-        if (!m_output.empty()) {
-            do_write();
-        }
-    }
-}
-
-void client::do_read()
-{
-    auto self = shared_from_this();
-
-    boost::asio::async_read_until(m_socket, m_input, "\r\n\r\n", [self] (auto code, auto xfer) {
-        self->handle_read(code, xfer);
-    });
-}
-
-void client::do_write()
-{
-    assert(!m_output.empty());
-
-    auto self = shared_from_this();
-
-    boost::asio::async_write(m_socket, boost::asio::buffer(m_output[0]), [self] (auto code, auto xfer) {
-        self->handle_write(code, xfer);
-    });
-}
-
-client::client(server& server, boost::asio::io_service& service, boost::asio::ssl::context& context)
-    : m_server(server)
-    , m_socket(service, context)
-{
-}
-
-void client::handshake()
-{
-    auto self = shared_from_this();
-
-    m_socket.async_handshake(boost::asio::ssl::stream_base::server, [self] (auto code) {
-        if (code) {
-            std::cerr << "handshake failure: " << code << std::endl;
-        } else {
-            self->read();
-        }
-    });
-}
-
-void client::read()
-{
-    do_read();
-}
-
-void client::send(std::string cmd, std::string data)
-{
-    send_raw(cmd + " " + data);
-}
-
-void client::ok(std::string cmd)
-{
-    send_raw(cmd + " ok");
-}
-
-void client::error(std::string cmd, std::string reason)
-{
-    send_raw(cmd + " error " + reason);
-}
-
-client_proxy_writer client::send(std::string cmd)
-{
-    return client_proxy_writer(shared_from_this(), cmd + " ");
-}
-
-void client::send_raw(std::string data)
-{
-    assert(!data.empty());
-
-    auto in_progress = !m_output.empty();
-
-    data += "\r\n\r\n";
-    m_output.push_back(std::move(data));
-
-    if (!in_progress) {
-        do_write();
-    }
-}
-
-} // !mlk
--- a/libserver/malikania/client.hpp	Sun Jan 22 11:07:36 2017 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,121 +0,0 @@
-#ifndef MALIKANIA_SERVER_CLIENT_HPP
-#define MALIKANIA_SERVER_CLIENT_HPP
-
-#include <cstdint>
-#include <deque>
-#include <memory>
-#include <string>
-#include <sstream>
-
-#include <boost/asio.hpp>
-#include <boost/asio/ssl.hpp>
-
-namespace mlk {
-
-class client;
-class server;
-
-class client_proxy_writer {
-    std::shared_ptr<client> m_client;
-    std::ostringstream m_output;
-
-public:
-    client_proxy_writer(std::shared_ptr<client> client, std::string init);
-
-    client_proxy_writer(client_proxy_writer&&) = default;
-
-    ~client_proxy_writer();
-
-    template <typename Arg>
-    inline client_proxy_writer& operator<<(Arg&& arg)
-    {
-        m_output << std::forward<Arg>(arg);
-
-        return *this;
-    }
-};
-
-class client : public std::enable_shared_from_this<client> {
-public:
-    friend class server;
-
-    enum class state : std::uint8_t {
-        authenticating,
-        ready
-    };
-
-private:
-    server& m_server;
-    state m_state{state::authenticating};
-    boost::asio::ssl::stream<boost::asio::ip::tcp::socket> m_socket;
-    boost::asio::streambuf m_input;
-    std::deque<std::string> m_output;
-
-    void handle_read(boost::system::error_code, std::size_t);
-    void handle_write(boost::system::error_code, std::size_t);
-
-    void do_read();
-    void do_write();
-
-    void handshake();
-    void read();
-
-public:
-    /**
-     * Create the client in the associated server.
-     *
-     * \param server the server object
-     * \param service the main loop service
-     * \param context the ssl context
-     */
-    client(server& server, boost::asio::io_service& service, boost::asio::ssl::context& context);
-
-    /**
-     * Send a command and its arguments.
-     *
-     * \pre !cmd.empty()
-     * \param cmd the command
-     * \param args the arguments
-     */
-    void send(std::string cmd, std::string args);
-
-    /**
-     * Send successful command result.
-     *
-     * \pre !cmd.empty()
-     * \param cmd the command name
-     */
-    void ok(std::string cmd);
-
-    /**
-     * Send a error command result.
-     *
-     * \pre !cmd.empty() && !reason.empty()
-     * \param cmd the command name
-     * \param reason the reason string
-     */
-    void error(std::string cmd, std::string reason);
-
-    /**
-     * Convenient function for sending data using operator<<.
-     *
-     * The returned have operator<< defined for the user and will append all
-     * data inserted that way when the appropriate client_proxy_write is
-     * destroyed.
-     *
-     * \param cmd the command name
-     */
-    client_proxy_writer send(std::string cmd);
-
-    /**
-     * Send a raw data.
-     *
-     * \pre !data.empty()
-     * \param data the data
-     */
-    void send_raw(std::string data);
-};
-
-} // !mlk
-
-#endif // !MALIKANIA_SERVER_CLIENT_HPP
--- a/libserver/malikania/database.cpp	Sun Jan 22 11:07:36 2017 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-/*
- * database.cpp -- generic database loader
- *
- * Copyright (c) 2013-2017 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <boost/filesystem.hpp>
-
-#include <stdexcept>
-
-#include "database.hpp"
-#include "util.hpp"
-
-namespace mlk {
-
-namespace {
-
-using load_func = void (const database_settings&);
-using unload_func = void ();
-
-boost::filesystem::path path(const database_settings& params)
-{
-    auto it = params.find("type");
-
-    if (it == params.end()) {
-        throw std::runtime_error("missing 'type' property");
-    }
-
-    boost::filesystem::path ret(util::basedir());
-
-    ret /= "lib";
-    ret /= "malikania";
-    ret /= "0.1.0";         // TODO: change this with an appropriate sysconfig.h
-    ret /= it->second;
-
-    return ret;
-}
-
-} // !namespace
-
-database::database(const database_settings& params)
-    : m_dso(path(params), boost::dll::load_mode::append_decorations)
-{
-    m_dso.get<load_func>("malikania_driver_load")(params);
-}
-
-database::~database()
-{
-    m_dso.get<unload_func>("malikania_driver_unload")();
-}
-
-} // !mlk
--- a/libserver/malikania/database.hpp	Sun Jan 22 11:07:36 2017 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +0,0 @@
-/*
- * database.hpp -- generic database loader
- *
- * Copyright (c) 2013-2017 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MALIKANIA_DATABASE_HPP
-#define MALIKANIA_DATABASE_HPP
-
-/**
- * \file database.hpp
- * \brief Generic database loader.
- */
-
-#include <boost/dll.hpp>
-
-#include <string>
-#include <unordered_map>
-
-namespace mlk {
-
-/**
- * Generic settings for database.
- */
-using database_settings = std::unordered_map<std::string, std::string>;
-
-/**
- * \brief Generic database.
- */
-class database {
-private:
-    boost::dll::shared_library m_dso;
-
-public:
-    /**
-     * Load the database driver dynamically.
-     *
-     * \param params the parameters to pass to the driver
-     * \throw std::exception on errors
-     */
-    database(const database_settings& params);
-
-    /**
-     * Close the database.
-     */
-    ~database();
-
-    /**
-     * Get the associated dso handle.
-     *
-     * \return the handle
-     */
-    inline const boost::dll::shared_library& handle() const noexcept
-    {
-        return m_dso;
-    }
-
-    /**
-     * Overloaded function
-     *
-     * \return the handle
-     */
-    inline boost::dll::shared_library& handle() noexcept
-    {
-        return m_dso;
-    }
-};
-
-} // !mlk
-
-#endif // !MALIKANIA_DATABASE_HPP
--- a/libserver/malikania/hash.hpp	Sun Jan 22 11:07:36 2017 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,262 +0,0 @@
-/*
- * hash.hpp -- hash functions
- *
- * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MALIKANIA_SERVER_HASH_HPP
-#define MALIKANIA_SERVER_HASH_HPP
-
-/**
- * \file hash.hpp
- * \brief Hash functions.
- * \author David Demelier <markand@malikania.fr>
- */
-
-/**
- * \brief Define buffer size.
- */
-#if !defined(HASH_BUFFER_SIZE)
-#   define HASH_BUFFER_SIZE 2048
-#endif
-
-#include <cassert>
-#include <istream>
-#include <iterator>
-#include <sstream>
-#include <string>
-
-#include <openssl/sha.h>
-#include <openssl/md5.h>
-
-/**
- * \brief Hash namespace.
- */
-namespace hash {
-
-/**
- * \cond HASH_HIDDEN_SYMBOLS
- */
-
-namespace detail {
-
-template <typename Context>
-using init_func = int (*)(Context *);
-
-template <typename Context>
-using update_func = int (*)(Context *, const void *, size_t);
-
-template <typename Context>
-using final_func = int (*)(unsigned char *, Context *);
-
-template <typename Context, size_t Length, typename InputIt>
-inline std::string convert(InputIt it,
-                           InputIt end,
-                           init_func<Context> init,
-                           update_func<Context> update,
-                           final_func<Context> finalize)
-{
-    unsigned char digest[Length] = { 0 };
-    char hash[Length * 2 + 1];
-    char buf[HASH_BUFFER_SIZE];
-
-    Context ctx;
-    init(&ctx);
-
-    while (it != end) {
-        unsigned i;
-
-        for (i = 0; it != end && i < HASH_BUFFER_SIZE; ++i) {
-            buf[i] = *it++;
-        }
-
-        update(&ctx, buf, i);
-    }
-
-    finalize(digest, &ctx);
-
-    for (unsigned long i = 0; i < Length; i++) {
-        std::snprintf(&hash[i * 2], 2 + 1, "%02x", static_cast<unsigned>(digest[i]));
-    }
-
-    return std::string(hash);
-}
-
-} // !namespace
-
-/**
- * \endcond
- */
-
-/**
- * \brief The scheme to use.
- */
-enum class scheme {
-    md5,        //!< MD5
-    sha1,       //!< SHA-1
-    sha256,     //!< SHA-256
-    sha512      //!< SHA-512
-};
-
-/**
- * Generic function.
- *
- * \param scheme the scheme to use
- * \param it the first character
- * \param end the last character
- * \return the string
- */
-template <typename InputIt>
-inline std::string to_string(scheme scheme, InputIt it, InputIt end)
-{
-    assert(scheme >= scheme::md5 && scheme <= scheme::sha512);
-
-    std::string result;
-
-    switch (scheme) {
-    case scheme::md5:
-        result = detail::convert<MD5_CTX, MD5_DIGEST_LENGTH>(it, end, MD5_Init, MD5_Update, MD5_Final);
-        break;
-    case scheme::sha1:
-        result = detail::convert<SHA_CTX, SHA_DIGEST_LENGTH>(it, end, SHA1_Init, SHA1_Update, SHA1_Final);;
-        break;
-    case scheme::sha256:
-        result = detail::convert<SHA256_CTX, SHA256_DIGEST_LENGTH>(it, end, SHA256_Init, SHA256_Update, SHA256_Final);
-        break;
-    case scheme::sha512:
-        result = detail::convert<SHA512_CTX, SHA512_DIGEST_LENGTH>(it, end, SHA512_Init, SHA512_Update, SHA512_Final);
-        break;
-    default:
-        break;
-    }
-
-    return result;
-}
-
-/**
- * Overload for std::istream.
- *
- * \param scheme the scheme to use
- * \param input the input stream
- * \return the string
- */
-inline std::string to_string(scheme scheme, std::istream &input)
-{
-    return to_string(scheme, std::istreambuf_iterator<char>(input), std::istreambuf_iterator<char>());
-}
-
-/**
- * Overload for std::string.
- *
- * \param scheme the scheme to use
- * \param input the input stream
- * \return the string
- */
-inline std::string to_string(scheme scheme, const std::string &input)
-{
-    return to_string(scheme, input.begin(), input.end());
-}
-
-/**
- * Hash using MD5.
- *
- * \param input the input string
- * \return the hashed string
- */
-inline std::string md5(const std::string &input)
-{
-    return to_string(scheme::md5, input);
-}
-
-/**
- * Hash using MD5.
- *
- * \param input the input stream
- * \return the hashed string
- */
-inline std::string md5(std::istream &input)
-{
-    return to_string(scheme::md5, input);
-}
-
-/**
- * Hash using SHA1.
- *
- * \param input the input string
- * \return the hashed string
- */
-inline std::string sha1(const std::string &input)
-{
-    return to_string(scheme::sha1, input);
-}
-
-/**
- * Hash using SHA1.
- *
- * \param input the input stream
- * \return the hashed string
- */
-inline std::string sha1(std::istream &input)
-{
-    return to_string(scheme::sha1, input);
-}
-
-/**
- * Hash using SHA256.
- *
- * \param input the input string
- * \return the hashed string
- */
-inline std::string sha256(const std::string &input)
-{
-    return to_string(scheme::sha256, input);
-}
-
-/**
- * Hash using SHA256.
- *
- * \param input the input stream
- * \return the hashed string
- */
-inline std::string sha256(std::istream &input)
-{
-    return to_string(scheme::sha256, input);
-}
-
-/**
- * Hash using SHA512.
- *
- * \param input the input string
- * \return the hashed string
- */
-inline std::string sha512(const std::string &input)
-{
-    return to_string(scheme::sha512, input);
-}
-
-/**
- * Hash using SHA512.
- *
- * \param input the input stream
- * \return the hashed string
- */
-inline std::string sha512(std::istream &input)
-{
-    return to_string(scheme::sha512, input);
-}
-
-} // !hash
-
-#endif // !MALIKANIA_SERVER_HASH_HPP
--- a/libserver/malikania/server.cpp	Sun Jan 22 11:07:36 2017 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,116 +0,0 @@
-/*
- * server.cpp -- malikania basic server
- *
- * Copyright (c) 2016-2017 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <iostream>
-
-#include "account_dao.hpp"
-#include "client.hpp"
-#include "server.hpp"
-#include "util.hpp"
-
-namespace mlk {
-
-void server::handle_auth(std::shared_ptr<client> clt, std::string args)
-{
-    std::cout << "== auth ==" << std::endl;
-
-    auto list = util::net::split(args);
-
-    if (list.size() != 2) {
-        clt->error("auth", "2 arguments required");
-    } else {
-        mlk::account_dao dao(m_database);
-
-        if (!dao.authenticate(list[0], list[1])) {
-            clt->error("auth", "invalid credential or inexistant account");
-        } else {
-            clt->ok("auth");
-        }
-    }
-}
-
-void server::start()
-{
-    auto clt = std::make_shared<client>(*this, m_service, m_context);
-
-    m_acceptor.async_accept(clt->m_socket.lowest_layer(), [this, clt] (auto code) {
-        this->handle_accept(std::move(clt), code);
-    });
-}
-
-boost::asio::ip::tcp::endpoint server::endpoint(const server_settings &params) const
-{
-    // TODO: add more settings there.
-    return boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), params.port);
-}
-
-server::server(boost::asio::io_service& service,
-               const server_settings& sv_params,
-               const database_settings& db_params)
-    : m_service(service)
-    , m_acceptor(service, endpoint(sv_params))
-    , m_context(boost::asio::ssl::context::sslv23)
-    , m_handlers{
-        { "auth", std::bind(&server::handle_auth, this, std::placeholders::_1, std::placeholders::_2) }
-    }
-    , m_database(db_params)
-{
-    m_context.use_certificate_chain_file(sv_params.certificate);
-    m_context.use_private_key_file(sv_params.key, boost::asio::ssl::context::pem);
-
-    start();
-}
-
-void server::add_handler(std::string cmd, handler func)
-{
-    m_handlers.emplace(std::move(cmd), std::move(func));
-}
-
-void server::handle_disconnect(std::shared_ptr<client> clt)
-{
-    std::cout << "client disconnected" << std::endl;
-    m_clients.erase(clt);
-}
-
-void server::handle_message(std::shared_ptr<client> clt, std::string cmd, std::string args)
-{
-    std::cout << "client sent:\n";
-    std::cout << "  -> cmd [" << cmd << "]\n";
-    std::cout << "  -> args [" << args << "]\n";
-
-    auto it = m_handlers.find(cmd);
-
-    if (it != m_handlers.end()) {
-        it->second(std::move(clt), std::move(args));
-    }
-}
-
-void server::handle_accept(std::shared_ptr<client> clt, boost::system::error_code code)
-{
-    if (code) {
-        std::cerr << "failed to accept: " << code << std::endl;
-    } else {
-        std::cout << "new client connected" << std::endl;
-        clt->handshake();
-        m_clients.insert(std::move(clt));
-    }
-
-    start();
-}
-
-} // !mlk
--- a/libserver/malikania/server.hpp	Sun Jan 22 11:07:36 2017 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +0,0 @@
-/*
- * server.hpp -- malikania basic server
- *
- * Copyright (c) 2016-2017 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MALIKANIA_SERVER_HPP
-#define MALIKANIA_SERVER_HPP
-
-#include <cstdint>
-#include <functional>
-#include <memory>
-#include <string>
-#include <unordered_map>
-#include <unordered_set>
-
-#include <boost/asio.hpp>
-#include <boost/asio/ssl.hpp>
-
-#include "database.hpp"
-
-namespace mlk {
-
-class client;
-
-class server_settings {
-public:
-    std::uint16_t port;
-    std::string certificate;
-    std::string key;
-};
-
-class server {
-public:
-    using handler = std::function<void (std::shared_ptr<client>, std::string)>;
-
-private:
-    boost::asio::io_service& m_service;
-    boost::asio::ip::tcp::acceptor m_acceptor;
-    boost::asio::ssl::context m_context;
-    std::unordered_set<std::shared_ptr<client>> m_clients;
-    std::unordered_map<std::string, handler> m_handlers;
-
-    database m_database;
-
-    void handle_auth(std::shared_ptr<client>, std::string);
-    void start();
-
-    boost::asio::ip::tcp::endpoint endpoint(const server_settings& params) const;
-
-public:
-    server(boost::asio::io_service& service,
-           const server_settings& sv_params,
-           const database_settings& db_params);
-
-    void add_handler(std::string cmd, handler func);
-
-    void handle_disconnect(std::shared_ptr<client>);
-
-    void handle_message(std::shared_ptr<client>, std::string, std::string);
-
-    void handle_accept(std::shared_ptr<client>, boost::system::error_code);
-};
-
-} // !mlk
-
-#endif // !MALIKANIA_SERVER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libserver/malikania/server/account.hpp	Sun Jan 22 17:54:56 2017 +0100
@@ -0,0 +1,61 @@
+/*
+ * account.hpp -- account model
+ *
+ * Copyright (c) 2013-2017 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MALIKANIA_ACCOUNT_HPP
+#define MALIKANIA_ACCOUNT_HPP
+
+/**
+ * \file account.hpp
+ * \brief Account model.
+ */
+
+#include <cstdint>
+#include <string>
+
+namespace mlk {
+
+namespace server {
+
+/**
+ * \brief Account model
+ */
+class account {
+public:
+    std::uint64_t id;
+    std::string name;
+    std::string email;
+    std::string first_name;
+    std::string last_name;
+    std::string password;
+};
+
+inline bool operator==(const account &ac1, const account &ac2) noexcept
+{
+    return ac1.id == ac2.id;
+}
+
+inline bool operator!=(const account &ac1, const account &ac2) noexcept
+{
+    return !(ac1 == ac2);
+}
+
+} // !server
+
+} // !mlk
+
+#endif // !MALIKANIA_ACCOUNT_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libserver/malikania/server/account_dao.cpp	Sun Jan 22 17:54:56 2017 +0100
@@ -0,0 +1,87 @@
+/*
+ * dao-account.cpp -- database account management
+ *
+ * Copyright (c) 2013-2017 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "account.hpp"
+#include "account_dao.hpp"
+#include "database.hpp"
+#include "hash.hpp"
+
+namespace mlk {
+
+namespace server {
+
+using create_func = void (account&);
+using remove_func = void (const account&);
+using update_func = void (account&);
+using get_func = boost::optional<account> (std::uint64_t);
+using find_by_name_func = boost::optional<account> (const std::string&);
+using list_func = std::vector<account> ();
+using count_func = std::uint64_t ();
+using clear_func = void ();
+
+bool account_dao::authenticate(const std::string& login, const std::string& pass)
+{
+    auto ac = find_by_name(login);
+    auto sha512 = hash::sha512(pass);
+
+    return ac && ac->password == sha512;
+}
+
+void account_dao::create(account& account)
+{
+    m_database.handle().get<create_func>("malikania_account_create")(account);
+}
+
+void account_dao::remove(const account& account)
+{
+    m_database.handle().get<remove_func>("malikania_account_remove")(account);
+}
+
+void account_dao::update(account& account)
+{
+    m_database.handle().get<update_func>("malikania_account_update")(account);
+}
+
+boost::optional<account> account_dao::get(uint64_t id)
+{
+    return m_database.handle().get<get_func>("malikania_account_get")(id);
+}
+
+boost::optional<account> account_dao::find_by_name(const std::string& name)
+{
+    return m_database.handle().get<find_by_name_func>("malikania_account_find_by_name")(name);
+}
+
+std::vector<account> account_dao::list()
+{
+    return m_database.handle().get<list_func>("malikania_account_list")();
+}
+
+std::uint64_t account_dao::count()
+{
+    return m_database.handle().get<count_func>("malikania_account_count")();
+}
+
+void account_dao::clear()
+{
+    m_database.handle().get<clear_func>("malikania_account_clear")();
+}
+
+} // !server
+
+} // !mlk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libserver/malikania/server/account_dao.hpp	Sun Jan 22 17:54:56 2017 +0100
@@ -0,0 +1,139 @@
+/*
+ * account_dao.hpp -- database account management
+ *
+ * Copyright (c) 2013-2017 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MALIKANIA_SERVER_ACCOUNT_DAO_HPP
+#define MALIKANIA_SERVER_ACCOUNT_DAO_HPP
+
+/**
+ * \file account_dao.hpp
+ * \brief Database account management.
+ */
+
+#include <cstdint>
+#include <vector>
+
+#include <boost/optional.hpp>
+
+namespace mlk {
+
+namespace server {
+
+class database;
+class account;
+
+/**
+ * \brief Account DAO.
+ */
+class account_dao {
+private:
+    database& m_database;
+
+public:
+    /**
+     * Constructor.
+     *
+     * \param database the database
+     */
+    inline account_dao(database& database) noexcept
+        : m_database(database)
+    {
+    }
+
+    /**
+     * Check if the user authentication is valid.
+     *
+     * \param login the login name
+     * \param pass the clear password
+     * \return true if authentication was successful
+     */
+    bool authenticate(const std::string& login, const std::string& pass);
+
+    /**
+     * Create the given account.
+     *
+     * The object will be modified in place.
+     *
+     * \param account the account to add
+     * \throw std::exception on errors
+     */
+    void create(account& account);
+
+    /**
+     * Remove the given account, all data that references this account is
+     * deleted too.
+     *
+     * \param account the account
+     * \throw std::exception on errors
+     */
+    void remove(const account& account);
+
+    /**
+     * Update account only, does not recurse into objects that references the
+     * account.
+     *
+     * \param account the account
+     * \throw std::exception on errors
+     */
+    void update(account& account);
+
+    /**
+     * Get an account.
+     *
+     * \param id the account id
+     * \return the account
+     * \throw std::exception if not found
+     */
+    boost::optional<account> get(std::uint64_t id);
+
+    /**
+     * Find an account by name.
+     *
+     * \param name the account name
+     * \return the account or empty one if not found
+     * \throw std::exception on other errors
+     */
+    boost::optional<account> find_by_name(const std::string& name);
+
+    /**
+     * Get the list of account.
+     *
+     * \throw std::exception on errors
+     */
+    std::vector<account> list();
+
+    /**
+     * Get the number of accounts.
+     *
+     * \return the number of account.
+     */
+    std::uint64_t count();
+
+    /**
+     * Remove all accounts recursively.
+     *
+     * \throw std::exception on errors
+     * \warning use with care
+     */
+    void clear();
+};
+
+} // !server
+
+} // !mlk
+
+#endif // !MALIKANIA_SERVER_ACCOUNT_DAO_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libserver/malikania/server/client.cpp	Sun Jan 22 17:54:56 2017 +0100
@@ -0,0 +1,161 @@
+#include <cassert>
+#include <iostream>
+
+#include "client.hpp"
+#include "server.hpp"
+
+namespace mlk {
+
+namespace server {
+
+/*
+ * client_proxy_writer
+ * ------------------------------------------------------------------
+ */
+
+client_proxy_writer::client_proxy_writer(std::shared_ptr<client> client, std::string init)
+    : m_client(std::move(client))
+{
+    assert(m_client);
+
+    m_output << init;
+}
+
+client_proxy_writer::~client_proxy_writer()
+{
+    m_client->send(m_output.str());
+}
+
+/*
+ * client_proxy_writer
+ * ------------------------------------------------------------------
+ */
+
+void client::handle_read(boost::system::error_code code, std::size_t xfer)
+{
+    // TODO: use fixed size stream + verify exceed.
+    if (code) {
+        m_server.handle_disconnect(shared_from_this());
+    } else {
+        std::istringstream iss(std::string(
+            boost::asio::buffers_begin(m_input.data()),
+            boost::asio::buffers_begin(m_input.data()) + xfer - 4
+        ));
+
+        // Remove early in case of errors.
+        m_input.consume(xfer);
+
+        // Extract command name.
+        std::string cmd;
+        iss >> cmd >> std::ws;
+
+        if (!iss) {
+            return;
+        }
+
+        // Rest of the data.
+        std::string data(std::istreambuf_iterator<char>(iss), {});
+
+        if (!iss) {
+            return;
+        }
+
+        m_server.handle_message(shared_from_this(), std::move(cmd), std::move(data));
+        do_read();
+    }
+}
+
+void client::handle_write(boost::system::error_code code, std::size_t)
+{
+    if (code) {
+        m_server.handle_disconnect(shared_from_this());
+    } else {
+        m_output.pop_front();
+
+        if (!m_output.empty()) {
+            do_write();
+        }
+    }
+}
+
+void client::do_read()
+{
+    auto self = shared_from_this();
+
+    boost::asio::async_read_until(m_socket, m_input, "\r\n\r\n", [self] (auto code, auto xfer) {
+        self->handle_read(code, xfer);
+    });
+}
+
+void client::do_write()
+{
+    assert(!m_output.empty());
+
+    auto self = shared_from_this();
+
+    boost::asio::async_write(m_socket, boost::asio::buffer(m_output[0]), [self] (auto code, auto xfer) {
+        self->handle_write(code, xfer);
+    });
+}
+
+client::client(server& server, boost::asio::io_service& service, boost::asio::ssl::context& context)
+    : m_server(server)
+    , m_socket(service, context)
+{
+}
+
+void client::handshake()
+{
+    auto self = shared_from_this();
+
+    m_socket.async_handshake(boost::asio::ssl::stream_base::server, [self] (auto code) {
+        if (code) {
+            std::cerr << "handshake failure: " << code << std::endl;
+        } else {
+            self->read();
+        }
+    });
+}
+
+void client::read()
+{
+    do_read();
+}
+
+void client::send(std::string cmd, std::string data)
+{
+    send_raw(cmd + " " + data);
+}
+
+void client::ok(std::string cmd)
+{
+    send_raw(cmd + " ok");
+}
+
+void client::error(std::string cmd, std::string reason)
+{
+    send_raw(cmd + " error " + reason);
+}
+
+client_proxy_writer client::send(std::string cmd)
+{
+    return client_proxy_writer(shared_from_this(), cmd + " ");
+}
+
+void client::send_raw(std::string data)
+{
+    assert(!data.empty());
+
+    auto in_progress = !m_output.empty();
+
+    data += "\r\n\r\n";
+    m_output.push_back(std::move(data));
+
+    if (!in_progress) {
+        do_write();
+    }
+}
+
+} // !server
+
+} // !mlk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libserver/malikania/server/client.hpp	Sun Jan 22 17:54:56 2017 +0100
@@ -0,0 +1,125 @@
+#ifndef MALIKANIA_SERVER_CLIENT_HPP
+#define MALIKANIA_SERVER_CLIENT_HPP
+
+#include <cstdint>
+#include <deque>
+#include <memory>
+#include <string>
+#include <sstream>
+
+#include <boost/asio.hpp>
+#include <boost/asio/ssl.hpp>
+
+namespace mlk {
+
+namespace server {
+
+class client;
+class server;
+
+class client_proxy_writer {
+    std::shared_ptr<client> m_client;
+    std::ostringstream m_output;
+
+public:
+    client_proxy_writer(std::shared_ptr<client> client, std::string init);
+
+    client_proxy_writer(client_proxy_writer&&) = default;
+
+    ~client_proxy_writer();
+
+    template <typename Arg>
+    inline client_proxy_writer& operator<<(Arg&& arg)
+    {
+        m_output << std::forward<Arg>(arg);
+
+        return *this;
+    }
+};
+
+class client : public std::enable_shared_from_this<client> {
+public:
+    friend class server;
+
+    enum class state : std::uint8_t {
+        authenticating,
+        ready
+    };
+
+private:
+    server& m_server;
+    state m_state{state::authenticating};
+    boost::asio::ssl::stream<boost::asio::ip::tcp::socket> m_socket;
+    boost::asio::streambuf m_input;
+    std::deque<std::string> m_output;
+
+    void handle_read(boost::system::error_code, std::size_t);
+    void handle_write(boost::system::error_code, std::size_t);
+
+    void do_read();
+    void do_write();
+
+    void handshake();
+    void read();
+
+public:
+    /**
+     * Create the client in the associated server.
+     *
+     * \param server the server object
+     * \param service the main loop service
+     * \param context the ssl context
+     */
+    client(server& server, boost::asio::io_service& service, boost::asio::ssl::context& context);
+
+    /**
+     * Send a command and its arguments.
+     *
+     * \pre !cmd.empty()
+     * \param cmd the command
+     * \param args the arguments
+     */
+    void send(std::string cmd, std::string args);
+
+    /**
+     * Send successful command result.
+     *
+     * \pre !cmd.empty()
+     * \param cmd the command name
+     */
+    void ok(std::string cmd);
+
+    /**
+     * Send a error command result.
+     *
+     * \pre !cmd.empty() && !reason.empty()
+     * \param cmd the command name
+     * \param reason the reason string
+     */
+    void error(std::string cmd, std::string reason);
+
+    /**
+     * Convenient function for sending data using operator<<.
+     *
+     * The returned have operator<< defined for the user and will append all
+     * data inserted that way when the appropriate client_proxy_write is
+     * destroyed.
+     *
+     * \param cmd the command name
+     */
+    client_proxy_writer send(std::string cmd);
+
+    /**
+     * Send a raw data.
+     *
+     * \pre !data.empty()
+     * \param data the data
+     */
+    void send_raw(std::string data);
+};
+
+} // !server
+
+} // !mlk
+
+#endif // !MALIKANIA_SERVER_CLIENT_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libserver/malikania/server/database.cpp	Sun Jan 22 17:54:56 2017 +0100
@@ -0,0 +1,68 @@
+/*
+ * database.cpp -- generic database loader
+ *
+ * Copyright (c) 2013-2017 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <boost/filesystem.hpp>
+
+#include <stdexcept>
+
+#include "database.hpp"
+#include "util.hpp"
+
+namespace mlk {
+
+namespace server {
+
+namespace {
+
+using load_func = void (const database_settings&);
+using unload_func = void ();
+
+boost::filesystem::path path(const database_settings& params)
+{
+    auto it = params.find("type");
+
+    if (it == params.end()) {
+        throw std::runtime_error("missing 'type' property");
+    }
+
+    boost::filesystem::path ret(util::basedir());
+
+    ret /= "lib";
+    ret /= "malikania";
+    ret /= "0.1.0";         // TODO: change this with an appropriate sysconfig.h
+    ret /= it->second;
+
+    return ret;
+}
+
+} // !namespace
+
+database::database(const database_settings& params)
+    : m_dso(path(params), boost::dll::load_mode::append_decorations)
+{
+    m_dso.get<load_func>("malikania_driver_load")(params);
+}
+
+database::~database()
+{
+    m_dso.get<unload_func>("malikania_driver_unload")();
+}
+
+} // !server
+
+} // !mlk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libserver/malikania/server/database.hpp	Sun Jan 22 17:54:56 2017 +0100
@@ -0,0 +1,87 @@
+/*
+ * database.hpp -- generic database loader
+ *
+ * Copyright (c) 2013-2017 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MALIKANIA_DATABASE_HPP
+#define MALIKANIA_DATABASE_HPP
+
+/**
+ * \file database.hpp
+ * \brief Generic database loader.
+ */
+
+#include <boost/dll.hpp>
+
+#include <string>
+#include <unordered_map>
+
+namespace mlk {
+
+namespace server {
+
+/**
+ * Generic settings for database.
+ */
+using database_settings = std::unordered_map<std::string, std::string>;
+
+/**
+ * \brief Generic database.
+ */
+class database {
+private:
+    boost::dll::shared_library m_dso;
+
+public:
+    /**
+     * Load the database driver dynamically.
+     *
+     * \param params the parameters to pass to the driver
+     * \throw std::exception on errors
+     */
+    database(const database_settings& params);
+
+    /**
+     * Close the database.
+     */
+    ~database();
+
+    /**
+     * Get the associated dso handle.
+     *
+     * \return the handle
+     */
+    inline const boost::dll::shared_library& handle() const noexcept
+    {
+        return m_dso;
+    }
+
+    /**
+     * Overloaded function
+     *
+     * \return the handle
+     */
+    inline boost::dll::shared_library& handle() noexcept
+    {
+        return m_dso;
+    }
+};
+
+} // !server
+
+} // !mlk
+
+#endif // !MALIKANIA_DATABASE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libserver/malikania/server/hash.hpp	Sun Jan 22 17:54:56 2017 +0100
@@ -0,0 +1,262 @@
+/*
+ * hash.hpp -- hash functions
+ *
+ * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MALIKANIA_SERVER_HASH_HPP
+#define MALIKANIA_SERVER_HASH_HPP
+
+/**
+ * \file hash.hpp
+ * \brief Hash functions.
+ * \author David Demelier <markand@malikania.fr>
+ */
+
+/**
+ * \brief Define buffer size.
+ */
+#if !defined(HASH_BUFFER_SIZE)
+#   define HASH_BUFFER_SIZE 2048
+#endif
+
+#include <cassert>
+#include <istream>
+#include <iterator>
+#include <sstream>
+#include <string>
+
+#include <openssl/sha.h>
+#include <openssl/md5.h>
+
+/**
+ * \brief Hash namespace.
+ */
+namespace hash {
+
+/**
+ * \cond HASH_HIDDEN_SYMBOLS
+ */
+
+namespace detail {
+
+template <typename Context>
+using init_func = int (*)(Context *);
+
+template <typename Context>
+using update_func = int (*)(Context *, const void *, size_t);
+
+template <typename Context>
+using final_func = int (*)(unsigned char *, Context *);
+
+template <typename Context, size_t Length, typename InputIt>
+inline std::string convert(InputIt it,
+                           InputIt end,
+                           init_func<Context> init,
+                           update_func<Context> update,
+                           final_func<Context> finalize)
+{
+    unsigned char digest[Length] = { 0 };
+    char hash[Length * 2 + 1];
+    char buf[HASH_BUFFER_SIZE];
+
+    Context ctx;
+    init(&ctx);
+
+    while (it != end) {
+        unsigned i;
+
+        for (i = 0; it != end && i < HASH_BUFFER_SIZE; ++i) {
+            buf[i] = *it++;
+        }
+
+        update(&ctx, buf, i);
+    }
+
+    finalize(digest, &ctx);
+
+    for (unsigned long i = 0; i < Length; i++) {
+        std::snprintf(&hash[i * 2], 2 + 1, "%02x", static_cast<unsigned>(digest[i]));
+    }
+
+    return std::string(hash);
+}
+
+} // !namespace
+
+/**
+ * \endcond
+ */
+
+/**
+ * \brief The scheme to use.
+ */
+enum class scheme {
+    md5,        //!< MD5
+    sha1,       //!< SHA-1
+    sha256,     //!< SHA-256
+    sha512      //!< SHA-512
+};
+
+/**
+ * Generic function.
+ *
+ * \param scheme the scheme to use
+ * \param it the first character
+ * \param end the last character
+ * \return the string
+ */
+template <typename InputIt>
+inline std::string to_string(scheme scheme, InputIt it, InputIt end)
+{
+    assert(scheme >= scheme::md5 && scheme <= scheme::sha512);
+
+    std::string result;
+
+    switch (scheme) {
+    case scheme::md5:
+        result = detail::convert<MD5_CTX, MD5_DIGEST_LENGTH>(it, end, MD5_Init, MD5_Update, MD5_Final);
+        break;
+    case scheme::sha1:
+        result = detail::convert<SHA_CTX, SHA_DIGEST_LENGTH>(it, end, SHA1_Init, SHA1_Update, SHA1_Final);;
+        break;
+    case scheme::sha256:
+        result = detail::convert<SHA256_CTX, SHA256_DIGEST_LENGTH>(it, end, SHA256_Init, SHA256_Update, SHA256_Final);
+        break;
+    case scheme::sha512:
+        result = detail::convert<SHA512_CTX, SHA512_DIGEST_LENGTH>(it, end, SHA512_Init, SHA512_Update, SHA512_Final);
+        break;
+    default:
+        break;
+    }
+
+    return result;
+}
+
+/**
+ * Overload for std::istream.
+ *
+ * \param scheme the scheme to use
+ * \param input the input stream
+ * \return the string
+ */
+inline std::string to_string(scheme scheme, std::istream &input)
+{
+    return to_string(scheme, std::istreambuf_iterator<char>(input), std::istreambuf_iterator<char>());
+}
+
+/**
+ * Overload for std::string.
+ *
+ * \param scheme the scheme to use
+ * \param input the input stream
+ * \return the string
+ */
+inline std::string to_string(scheme scheme, const std::string &input)
+{
+    return to_string(scheme, input.begin(), input.end());
+}
+
+/**
+ * Hash using MD5.
+ *
+ * \param input the input string
+ * \return the hashed string
+ */
+inline std::string md5(const std::string &input)
+{
+    return to_string(scheme::md5, input);
+}
+
+/**
+ * Hash using MD5.
+ *
+ * \param input the input stream
+ * \return the hashed string
+ */
+inline std::string md5(std::istream &input)
+{
+    return to_string(scheme::md5, input);
+}
+
+/**
+ * Hash using SHA1.
+ *
+ * \param input the input string
+ * \return the hashed string
+ */
+inline std::string sha1(const std::string &input)
+{
+    return to_string(scheme::sha1, input);
+}
+
+/**
+ * Hash using SHA1.
+ *
+ * \param input the input stream
+ * \return the hashed string
+ */
+inline std::string sha1(std::istream &input)
+{
+    return to_string(scheme::sha1, input);
+}
+
+/**
+ * Hash using SHA256.
+ *
+ * \param input the input string
+ * \return the hashed string
+ */
+inline std::string sha256(const std::string &input)
+{
+    return to_string(scheme::sha256, input);
+}
+
+/**
+ * Hash using SHA256.
+ *
+ * \param input the input stream
+ * \return the hashed string
+ */
+inline std::string sha256(std::istream &input)
+{
+    return to_string(scheme::sha256, input);
+}
+
+/**
+ * Hash using SHA512.
+ *
+ * \param input the input string
+ * \return the hashed string
+ */
+inline std::string sha512(const std::string &input)
+{
+    return to_string(scheme::sha512, input);
+}
+
+/**
+ * Hash using SHA512.
+ *
+ * \param input the input stream
+ * \return the hashed string
+ */
+inline std::string sha512(std::istream &input)
+{
+    return to_string(scheme::sha512, input);
+}
+
+} // !hash
+
+#endif // !MALIKANIA_SERVER_HASH_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libserver/malikania/server/server.cpp	Sun Jan 22 17:54:56 2017 +0100
@@ -0,0 +1,120 @@
+/*
+ * server.cpp -- malikania basic server
+ *
+ * Copyright (c) 2016-2017 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <iostream>
+
+#include "account_dao.hpp"
+#include "client.hpp"
+#include "server.hpp"
+#include "util.hpp"
+
+namespace mlk {
+
+namespace server {
+
+void server::handle_auth(std::shared_ptr<client> clt, std::string args)
+{
+    std::cout << "== auth ==" << std::endl;
+
+    auto list = util::net::split(args);
+
+    if (list.size() != 2) {
+        clt->error("auth", "2 arguments required");
+    } else {
+        account_dao dao(m_database);
+
+        if (!dao.authenticate(list[0], list[1])) {
+            clt->error("auth", "invalid credential or inexistant account");
+        } else {
+            clt->ok("auth");
+        }
+    }
+}
+
+void server::start()
+{
+    auto clt = std::make_shared<client>(*this, m_service, m_context);
+
+    m_acceptor.async_accept(clt->m_socket.lowest_layer(), [this, clt] (auto code) {
+        this->handle_accept(std::move(clt), code);
+    });
+}
+
+boost::asio::ip::tcp::endpoint server::endpoint(const server_settings &params) const
+{
+    // TODO: add more settings there.
+    return boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), params.port);
+}
+
+server::server(boost::asio::io_service& service,
+               const server_settings& sv_params,
+               const database_settings& db_params)
+    : m_service(service)
+    , m_acceptor(service, endpoint(sv_params))
+    , m_context(boost::asio::ssl::context::sslv23)
+    , m_handlers{
+        { "auth", std::bind(&server::handle_auth, this, std::placeholders::_1, std::placeholders::_2) }
+    }
+    , m_database(db_params)
+{
+    m_context.use_certificate_chain_file(sv_params.certificate);
+    m_context.use_private_key_file(sv_params.key, boost::asio::ssl::context::pem);
+
+    start();
+}
+
+void server::add_handler(std::string cmd, handler func)
+{
+    m_handlers.emplace(std::move(cmd), std::move(func));
+}
+
+void server::handle_disconnect(std::shared_ptr<client> clt)
+{
+    std::cout << "client disconnected" << std::endl;
+    m_clients.erase(clt);
+}
+
+void server::handle_message(std::shared_ptr<client> clt, std::string cmd, std::string args)
+{
+    std::cout << "client sent:\n";
+    std::cout << "  -> cmd [" << cmd << "]\n";
+    std::cout << "  -> args [" << args << "]\n";
+
+    auto it = m_handlers.find(cmd);
+
+    if (it != m_handlers.end()) {
+        it->second(std::move(clt), std::move(args));
+    }
+}
+
+void server::handle_accept(std::shared_ptr<client> clt, boost::system::error_code code)
+{
+    if (code) {
+        std::cerr << "failed to accept: " << code << std::endl;
+    } else {
+        std::cout << "new client connected" << std::endl;
+        clt->handshake();
+        m_clients.insert(std::move(clt));
+    }
+
+    start();
+}
+
+} // !server
+
+} // !mlk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libserver/malikania/server/server.hpp	Sun Jan 22 17:54:56 2017 +0100
@@ -0,0 +1,83 @@
+/*
+ * server.hpp -- malikania basic server
+ *
+ * Copyright (c) 2016-2017 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MALIKANIA_SERVER_HPP
+#define MALIKANIA_SERVER_HPP
+
+#include <cstdint>
+#include <functional>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+#include <boost/asio.hpp>
+#include <boost/asio/ssl.hpp>
+
+#include "database.hpp"
+
+namespace mlk {
+
+namespace server {
+
+class client;
+
+class server_settings {
+public:
+    std::uint16_t port;
+    std::string certificate;
+    std::string key;
+};
+
+class server {
+public:
+    using handler = std::function<void (std::shared_ptr<client>, std::string)>;
+
+private:
+    boost::asio::io_service& m_service;
+    boost::asio::ip::tcp::acceptor m_acceptor;
+    boost::asio::ssl::context m_context;
+    std::unordered_set<std::shared_ptr<client>> m_clients;
+    std::unordered_map<std::string, handler> m_handlers;
+
+    database m_database;
+
+    void handle_auth(std::shared_ptr<client>, std::string);
+    void start();
+
+    boost::asio::ip::tcp::endpoint endpoint(const server_settings& params) const;
+
+public:
+    server(boost::asio::io_service& service,
+           const server_settings& sv_params,
+           const database_settings& db_params);
+
+    void add_handler(std::string cmd, handler func);
+
+    void handle_disconnect(std::shared_ptr<client>);
+
+    void handle_message(std::shared_ptr<client>, std::string, std::string);
+
+    void handle_accept(std::shared_ptr<client>, boost::system::error_code);
+};
+
+} // !server
+
+} // !mlk
+
+#endif // !MALIKANIA_SERVER_HPP
--- a/server/main.cpp	Sun Jan 22 11:07:36 2017 +0100
+++ b/server/main.cpp	Sun Jan 22 17:54:56 2017 +0100
@@ -18,17 +18,17 @@
 
 #include <iostream>
 
-#include <malikania/server.hpp>
+#include <malikania/server/server.hpp>
 
 int main()
 {
-    mlk::server_settings sv_params;
+    mlk::server::server_settings sv_params;
 
     sv_params.port = 3320;
     sv_params.certificate = "/home/markand/null/server.crt";
     sv_params.key = "/home/markand/null/server.key";
 
-    mlk::database_settings db_params;
+    mlk::server::database_settings db_params;
 
     db_params["type"] = "sqlite";
     db_params["path"] = "/home/markand/kingdom.db";
@@ -36,7 +36,7 @@
     boost::asio::io_service service;
 
     try {
-        mlk::server server(service, sv_params, db_params);
+        mlk::server::server server(service, sv_params, db_params);
 
         for (;;) {
             service.run();