| Home | Libraries | People | FAQ | More

# allocation/server.cpp

    #include <cstdlib>
    #include <iostream>
    #include <boost/aligned_storage.hpp>
    #include <boost/array.hpp>
    #include <boost/bind.hpp>
    #include <boost/enable_shared_from_this.hpp>
    #include <boost/noncopyable.hpp>
    #include <boost/shared_ptr.hpp>
    #include <boost/asio.hpp>

    using boost::asio::ip::tcp;

    // Class to manage the memory to be used for handler-based custom allocation.
    // It contains a single block of memory which may be returned for allocation
    // requests. If the memory is in use when an allocation request is made, the
    // allocator delegates allocation to the global heap.
    class handler_allocator
      : private boost::noncopyable
    {
    public:
      handler_allocator()
        : in_use_(false)
      {
      }

      void* allocate(std::size_t size)
      {
        if (!in_use_ && size < storage_.size)
        {
          in_use_ = true;
          return storage_.address();
        }
        else
        {
          return ::operator new(size);
        }
      }

      void deallocate(void* pointer)
      {
        if (pointer == storage_.address())
        {
          in_use_ = false;
        }
        else
        {
          ::operator delete(pointer);
        }
      }

    private:
      // Storage space used for handler-based custom memory allocation.
      boost::aligned_storage<1024> storage_;

      // Whether the handler-based custom allocation storage has been used.
      bool in_use_;
    };

    // Wrapper class template for handler objects to allow handler memory
    // allocation to be customised. Calls to operator() are forwarded to the
    // encapsulated handler.
    template <typename Handler>
    class custom_alloc_handler
    {
    public:
      custom_alloc_handler(handler_allocator& a, Handler h)
        : allocator_(a),
          handler_(h)
      {
      }

      template <typename Arg1>
      void operator()(Arg1 arg1)
      {
        handler_(arg1);
      }

      template <typename Arg1, typename Arg2>
      void operator()(Arg1 arg1, Arg2 arg2)
      {
        handler_(arg1, arg2);
      }

      friend void* asio_handler_allocate(std::size_t size,
          custom_alloc_handler<Handler>* this_handler)
      {
        return this_handler->allocator_.allocate(size);
      }

      friend void asio_handler_deallocate(void* pointer, std::size_t size,
          custom_alloc_handler<Handler>* this_handler)
      {
        this_handler->allocator_.deallocate(pointer);
      }

    private:
      handler_allocator& allocator_;
      Handler handler_;
    };

    // Helper function to wrap a handler object to add custom allocation.
    template <typename Handler>
    inline custom_alloc_handler<Handler> make_custom_alloc_handler(
        handler_allocator& a, Handler h)
    {
      return custom_alloc_handler<Handler>(a, h);
    }

    class session
      : public boost::enable_shared_from_this<session>
    {
    public:
      session(boost::asio::io_service& io_service)
        : socket_(io_service)
      {
      }

      tcp::socket& socket()
      {
        return socket_;
      }

      void start()
      {
        socket_.async_read_some(boost::asio::buffer(data_),
            make_custom_alloc_handler(allocator_,
              boost::bind(&session::handle_read,
                shared_from_this(),
                boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred)));
      }

      void handle_read(const boost::asio::error& error, size_t bytes_transferred)
      {
        if (!error)
        {
          boost::asio::async_write(socket_,
              boost::asio::buffer(data_, bytes_transferred),
              make_custom_alloc_handler(allocator_,
                boost::bind(&session::handle_write,
                  shared_from_this(),
                  boost::asio::placeholders::error)));
        }
      }

      void handle_write(const boost::asio::error& error)
      {
        if (!error)
        {
          socket_.async_read_some(boost::asio::buffer(data_),
              make_custom_alloc_handler(allocator_,
                boost::bind(&session::handle_read,
                  shared_from_this(),
                  boost::asio::placeholders::error,
                  boost::asio::placeholders::bytes_transferred)));
        }
      }

    private:
      // The socket used to communicate with the client.
      tcp::socket socket_;

      // Buffer used to store data received from the client.
      boost::array<char, 1024> data_;

      // The allocator to use for handler-based custom memory allocation.
      handler_allocator allocator_;
    };

    typedef boost::shared_ptr<session> session_ptr;

    class server
    {
    public:
      server(boost::asio::io_service& io_service, short port)
        : io_service_(io_service),
          acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
      {
        session_ptr new_session(new session(io_service_));
        acceptor_.async_accept(new_session->socket(),
            boost::bind(&server::handle_accept, this, new_session,
              boost::asio::placeholders::error));
      }

      void handle_accept(session_ptr new_session, const boost::asio::error& error)
      {
        if (!error)
        {
          new_session->start();
          new_session.reset(new session(io_service_));
          acceptor_.async_accept(new_session->socket(),
              boost::bind(&server::handle_accept, this, new_session,
                boost::asio::placeholders::error));
        }
      }

    private:
      boost::asio::io_service& io_service_;
      tcp::acceptor acceptor_;
    };

    int main(int argc, char* argv[])
    {
      try
      {
        if (argc != 2)
        {
          std::cerr << "Usage: server <port>\n";
          return 1;
        }

        boost::asio::io_service io_service;

        using namespace std; // For atoi.
        server s(io_service, atoi(argv[1]));

        io_service.run();
      }
      catch (boost::asio::error& e)
      {
        std::cerr << e << "\n";
      }
      catch (std::exception& e)
      {
        std::cerr << "Exception: " << e.what() << "\n";
      }

      return 0;
    }

| Copyright © 2003 - 2006 Christopher M. Kohlhoff