Xirema

Basic Server.h

Feb 17th, 2016
96
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.04 KB | None | 0 0
  1. #pragma once
  2. #define ASIO_STANDALONE
  3. #define ASIO_HAS_STD_ADDRESSOF
  4. #define ASIO_HAS_STD_ARRAY
  5. #define ASIO_HAS_CSTDINT
  6. #define ASIO_HAS_STD_SHARED_PTR
  7. #define ASIO_HAS_STD_TYPE_TRAITS
  8. #include<asio.hpp>
  9. #include<asio/placeholders.hpp>
  10. #include<vector>
  11. #include<thread>
  12. #include<string>
  13. #include<iostream>
  14. #include<iomanip>
  15. #include<chrono>
  16. #include<sstream>
  17. #include<random>
  18. #include<functional>
  19. #include<fstream>
  20. #include<memory>
  21. #include<exception>
  22. #include<set>
  23. #include<tuple>
  24. #include<iostream>
  25.  
  26. #include<array>
  27. #include<map>
  28.  
  29. #include "Concurrent Queue.h"
  30. #include "Concurrent Map.h"
  31.  
  32. namespace server {
  33.  
  34.     constexpr inline unsigned long long power_function(const unsigned long long prime, const unsigned long long iterations) {
  35.         return
  36.             /*iterations >= 1'048'576 ? prime * power_function(prime, 1'048'575) * power_function(prime, iterations - 1'048'576) :
  37.             iterations >= 65'536 ? prime * power_function(prime, 65'535) * power_function(prime, iterations - 65'536) :
  38.             iterations >= 4'096 ? prime * power_function(prime, 4'095) * power_function(prime, iterations - 4'096) :*/
  39.             iterations >= 256 ? prime * power_function(prime, 255) * power_function(prime, iterations - 256) :
  40.             iterations >= 16 ? prime * power_function(prime, 15) * power_function(prime, iterations - 16) :
  41.             iterations > 0 ? prime * power_function(prime, iterations - 1) : 1;
  42.     }
  43.  
  44.     inline unsigned long long getSeed() {
  45.         return std::chrono::steady_clock::now().time_since_epoch().count();
  46.     }
  47.  
  48.     union connection_id {
  49.     private:
  50.         static constexpr unsigned long long prime = power_function(-363, 30'000);
  51.         unsigned long long permute_seed(unsigned long long seed) {
  52.             return (seed + 1) * 59 * prime;
  53.         }
  54.     public:
  55.         unsigned long long l;
  56.         unsigned char c[8];
  57.  
  58.         connection_id() :
  59.             l(0)
  60.         {
  61.  
  62.         }
  63.  
  64.         connection_id(unsigned long long seed) :
  65.             l(permute_seed(seed))
  66.         {
  67.         }
  68.         bool operator<(const connection_id & c) const {
  69.             return l < c.l;
  70.         }
  71.         bool operator==(const connection_id & c) const {
  72.             return l == c.l;
  73.         }
  74.  
  75.         connection_id & operator=(unsigned long long seed) {
  76.             l = permute_seed(seed);
  77.             return *this;
  78.         }
  79.  
  80.         connection_id & operator=(const connection_id & id) {
  81.             if (this == &id) return *this;
  82.             l = id.l;
  83.             return *this;
  84.         }
  85.  
  86.         std::string str() const {
  87.             std::stringstream ss;
  88.             static const std::set<int> dash_indexes = {0, 5, 10};
  89.             ss << std::hex;
  90.             ss << std::uppercase;
  91.             for (int i = 0; i < 16; i++) {
  92.                 int byte_index = i / 2;
  93.                 int byte_half = (i + 1) % 2;
  94.                 unsigned int value = (c[byte_index] >> (byte_half * 4)) & 0xF;
  95.                 ss << value;
  96.                 if (dash_indexes.count(i)) ss << "-";
  97.             }
  98.             return ss.str();
  99.         }
  100.  
  101.         operator std::string() const {
  102.             return str();
  103.         }
  104.  
  105.         friend std::ostream & operator<<(std::ostream & os, const connection_id & id);
  106.     };
  107.  
  108.     std::ostream & operator<<(std::ostream & os, const connection_id & id) {
  109.         return os << id.str();
  110.     }
  111.  
  112.     typedef std::unique_ptr<asio::ip::tcp::socket> socket_ptr;
  113.     static const size_t MAX_BUFFER_SIZE = 1'048'576;
  114.     typedef std::array<unsigned char, MAX_BUFFER_SIZE> data_buffer_type;
  115.     typedef std::unique_ptr<data_buffer_type> data_buffer;
  116.  
  117.     class connection {
  118.     private:
  119.         socket_ptr socket;
  120.         connection_id id;
  121.         std::string ip_address;
  122.         std::string port;
  123.  
  124.     public:
  125.         data_buffer read_buffer;
  126.  
  127.         connection(unsigned long long seed, asio::io_service& service, std::string ip, std::string _port) :
  128.             id(seed),
  129.             socket(socket_ptr(new asio::ip::tcp::socket(service))),
  130.             ip_address(ip),
  131.             port(_port),
  132.             read_buffer(new data_buffer_type())
  133.         {
  134.         }
  135.  
  136.         connection(const connection_id & _id, asio::io_service & service, std::string ip, std::string _port) :
  137.             id(_id),
  138.             socket(socket_ptr(new asio::ip::tcp::socket(service))),
  139.             ip_address(ip),
  140.             port(_port),
  141.             read_buffer(new data_buffer_type())
  142.         {
  143.         }
  144.  
  145.         bool operator<(const connection & c) const {
  146.             return id < c.id;
  147.         }
  148.  
  149.         bool operator==(const connection & c) const {
  150.             return id == c.id;
  151.         }
  152.  
  153.         asio::ip::tcp::socket & get_socket() const {
  154.             return *socket;
  155.         }
  156.  
  157.         std::string get_ip_address() {
  158.             return ip_address;
  159.         }
  160.  
  161.         std::string get_port() {
  162.             return port;
  163.         }
  164.  
  165.         connection_id get_id() const { return id; }
  166.         void regen_id(unsigned long long seed) {
  167.             id = seed;
  168.         }
  169.     };
  170.  
  171.     typedef std::vector<unsigned char> data_vector;
  172.     typedef std::pair<connection_id, data_vector> data_pair;
  173.     typedef concurrent::queue<data_pair> data_queue;
  174.  
  175.     typedef std::shared_ptr<connection> connection_ptr;
  176.     typedef concurrent::map<connection_id, connection_ptr> connection_map;
  177.     typedef unsigned long long buffer_id;
  178.     typedef concurrent::map<buffer_id, data_vector> write_buffer_map;
  179.     typedef std::unique_ptr<asio::io_service> service_ptr;
  180.     typedef std::unique_ptr<asio::io_service::work> work_ptr;
  181.     typedef std::unique_ptr<asio::ip::tcp::acceptor> acceptor_ptr;
  182.  
  183.     class basic_server {
  184.     private:
  185.         service_ptr service;
  186.         work_ptr work;
  187.         acceptor_ptr acceptor;
  188.         connection_id client_connection;
  189.         connection_map connections;
  190.         std::mutex mutex;
  191.         std::condition_variable cond;
  192.         volatile bool running;
  193.         data_queue read_queue;
  194.         write_buffer_map write_buffers;
  195.         buffer_id current_buffer_id;
  196.         std::ofstream lout;
  197.  
  198.         std::thread service_thread;
  199.  
  200.         buffer_id get_next_buffer_id() {
  201.             return current_buffer_id++;
  202.         }
  203.  
  204.         void service_function() {
  205.             asio::error_code ec;
  206.             while (!running) std::this_thread::yield();
  207.             while (running) {
  208.                 try {
  209.                     service->run(ec);
  210.                     break;
  211.                 }
  212.                 catch (std::exception & e) {
  213.                     lout << "ERROR: " << e.what() << std::endl;
  214.                 }
  215.             }
  216.         }
  217.  
  218.         void accept(const asio::error_code & ec, const connection_id & id) {
  219.             if (ec) {
  220.                 connections.erase(id);
  221.                 return;
  222.             }
  223.             using namespace std::chrono_literals;
  224.             connection_ptr conn = connections[id];
  225.             conn->get_socket().async_read_some(
  226.                 asio::buffer(
  227.                     &conn->read_buffer->front(),
  228.                     MAX_BUFFER_SIZE
  229.                 ),
  230.                 std::bind(
  231.                     &basic_server::read,
  232.                     this,
  233.                     std::placeholders::_1,
  234.                     std::placeholders::_2,
  235.                     id
  236.                 )
  237.             );
  238.             connection_id nid(getSeed());
  239.             while (connections.contains(nid)) {
  240.                 std::this_thread::sleep_for(std::chrono::milliseconds(1));
  241.                 nid = getSeed();
  242.             }
  243.             connections[nid] = connection_ptr(new connection(nid, *service, conn->get_ip_address(), conn->get_port()));
  244.             connection_ptr nconn = connections[nid];
  245.             acceptor->async_accept(
  246.                 nconn->get_socket(),
  247.                 std::bind(
  248.                     &basic_server::accept,
  249.                     this,
  250.                     std::placeholders::_1,
  251.                     nid
  252.                 )
  253.             );
  254.         }
  255.  
  256.         void connect(const asio::error_code & ec, const connection_id & id) {
  257.             if (ec) {
  258.                 connections.erase(id);
  259.                 return;
  260.             }
  261.             connection_ptr conn = connections[id];
  262.             conn->get_socket().async_read_some(
  263.                 asio::buffer(
  264.                     &conn->read_buffer->front(),
  265.                     MAX_BUFFER_SIZE
  266.                 ),
  267.                 std::bind(
  268.                     &basic_server::read,
  269.                     this,
  270.                     std::placeholders::_1,
  271.                     std::placeholders::_2,
  272.                     id
  273.                 )
  274.             );
  275.         }
  276.  
  277.         void read(const asio::error_code & ec, size_t bytes_read, const connection_id & id) {
  278.             if (ec) {
  279.                 connections.erase(id);
  280.                 return;
  281.             }
  282.             connection_ptr conn = connections[id];
  283.             data_vector queue_data;
  284.             queue_data.insert(queue_data.end(), conn->read_buffer->begin(), conn->read_buffer->begin() + bytes_read);
  285.             read_queue.push(data_pair(id, queue_data));
  286.  
  287.             conn->get_socket().async_read_some(
  288.                 asio::buffer(
  289.                     &conn->read_buffer->front(),
  290.                     MAX_BUFFER_SIZE
  291.                 ),
  292.                 std::bind(
  293.                     &basic_server::read,
  294.                     this,
  295.                     std::placeholders::_1,
  296.                     std::placeholders::_2,
  297.                     id
  298.                 )
  299.             );
  300.         }
  301.  
  302.         void write(const asio::error_code & ec, size_t bytes_written, const connection_id & id, buffer_id buf_id) {
  303.             write_buffers.erase(buf_id);
  304.             if (ec) {
  305.                 connections.erase(id);
  306.             }
  307.         }
  308.     public:
  309.         basic_server() :
  310.             service(new asio::io_service()),
  311.             work(new asio::io_service::work(*service)),
  312.             acceptor(new asio::ip::tcp::acceptor(*service)),
  313.             running(true),
  314.             service_thread(std::bind(&basic_server::service_function, this)),
  315.             lout("server.log"),
  316.             current_buffer_id(0)
  317.         {
  318.         }
  319.  
  320.         void start_listening(const std::string & ip_address, const std::string & port) {
  321.             asio::ip::tcp::resolver resolver(*service);
  322.             asio::ip::tcp::resolver::query query(ip_address, port);
  323.             asio::ip::tcp::endpoint endpoint = *(resolver.resolve(query));
  324.  
  325.             acceptor->open(endpoint.protocol());
  326.             acceptor->bind(endpoint);
  327.             acceptor->listen(asio::socket_base::max_connections);
  328.  
  329.             connection_id id(getSeed());
  330.             connections[id] = connection_ptr(new connection(id, *service, ip_address, port));
  331.             connection_ptr conn = connections[id];
  332.  
  333.             acceptor->async_accept(
  334.                 conn->get_socket(),
  335.                 std::bind(
  336.                     &basic_server::accept,
  337.                     this,
  338.                     std::placeholders::_1,
  339.                     id
  340.                 )
  341.             );
  342.         }
  343.  
  344.         void start_connecting(const std::string & ip_address, const std::string & port) {
  345.             asio::ip::tcp::resolver resolver(*service);
  346.             asio::ip::tcp::resolver::query query(ip_address, port);
  347.             asio::ip::tcp::endpoint endpoint = *(resolver.resolve(query));
  348.  
  349.             connection_id id(getSeed());
  350.             connections[id] = connection_ptr(new connection(id, *service, ip_address, port));
  351.             connection_ptr conn = connections[id];
  352.             client_connection = id;
  353.  
  354.             conn->get_socket().async_connect(
  355.                 endpoint,
  356.                 std::bind(
  357.                     &basic_server::connect,
  358.                     this,
  359.                     std::placeholders::_1,
  360.                     id
  361.                 )
  362.             );
  363.         }
  364.  
  365.         ~basic_server() {
  366.             stop();
  367.             service_thread.join();
  368.         }
  369.  
  370.         bool read_from_queue(data_pair & data) {
  371.             return read_queue.try_pop(data);
  372.         }
  373.  
  374.         void write_to_connection(const connection_id & id, const data_vector & data) {
  375.             if (connections.contains(id)) {
  376.                 buffer_id bid = get_next_buffer_id();
  377.                 write_buffers[bid] = data;
  378.                 data_vector & saved_buffer = write_buffers[bid];
  379.                 connection_ptr conn = connections[id];
  380.                 conn->get_socket().async_write_some(
  381.                     asio::buffer(
  382.                         &saved_buffer.front(),
  383.                         saved_buffer.size()
  384.                     ),
  385.                     std::bind(
  386.                         &basic_server::write,
  387.                         this,
  388.                         std::placeholders::_1,
  389.                         std::placeholders::_2,
  390.                         id,
  391.                         bid
  392.                     )
  393.                 );
  394.             }
  395.         }
  396.  
  397.         void write_to_connection(const connection_id & id, const void * data, size_t size_of_data) {
  398.             data_vector vector(size_of_data);
  399.             const unsigned char * data_ptr = static_cast<const unsigned char *>(data);
  400.             std::copy(data_ptr, data_ptr + size_of_data, vector.begin());
  401.             write_to_connection(id, vector);
  402.         }
  403.  
  404.         void client_write(const data_vector & data) {
  405.             connection_id id = client_connection;
  406.             write_to_connection(id, data);
  407.         }
  408.  
  409.         void stop() {
  410.             running = false;
  411.             work.reset();
  412.             service->stop();
  413.             read_queue.wake_all();
  414.         }
  415.  
  416.         std::set<connection_id> get_all_connection_ids() const {
  417.             return connections.getKeySet();
  418.         }
  419.  
  420.         bool is_connected(const connection_id & id) const {
  421.             return connections.contains(id);
  422.         }
  423.  
  424.         const connection_ptr get_connection(const connection_id & id) const {
  425.             return connections.at(id);
  426.         }
  427.     };
  428. }
Add Comment
Please, Sign In to add comment