#pragma once #include "stdafx.h" #include "mMindErrors.h" #include "mMindThread.h" //#include #include using boost::asio::ip::tcp; //Hugely from http://www.boost.org/doc/libs/1_36_0/doc/html/boost_asio/example/echo/async_tcp_echo_server.cpp class mMindServerHandlerClient { friend class mMindThreadServerListener; friend class mMindThreadConnectionPruner; public: unsigned long max_buffer_size; private: tcp::socket _socket; char* _data; bool _errored; public: mMindServerHandlerClient(unsigned long new_max_buffer_size, boost::asio::io_service& io_service) : _socket(io_service) { max_buffer_size = new_max_buffer_size; _data = new char[max_buffer_size]; _errored = false; } ~mMindServerHandlerClient() { delete [] _data; } public: void function(const char* data, unsigned long data_length) { //logic based on content of "data" goes here. We then return //new data (for now, we're returning just the same thing). send((char*)data,data_length); } const char* read(void) { _socket.async_read_some( boost::asio::buffer(_data,max_buffer_size), boost::bind( &mMindServerHandlerClient::mMindInternal_handle_read, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred ) ); return _data; } void send(char* data="", unsigned long data_length=0) { boost::asio::async_write( _socket, boost::asio::buffer(data,max_buffer_size), boost::bind( &mMindServerHandlerClient::mMindInternal_handle_write, this, boost::asio::placeholders::error ) ); } private: void mMindInternal_start(void) { read(); char* welcome = "Server sending welcome"; send(welcome,strlen(welcome)); } void mMindInternal_handle_read(const boost::system::error_code& error, size_t bytes_transferred) { if (error) { _errored = true; return; } //After read, process data, and send a response back function(_data,bytes_transferred); } void mMindInternal_handle_write(const boost::system::error_code& error) { if (error) { _errored = true; return; } //After write, wait for input read(); } }; class mMindThreadConnectionPruner : public mMindThread { private: list* _connections; public: mMindThreadConnectionPruner(list* connections) : mMindThread() { _connections = connections; } void function(void) { list::iterator iter1, iter2; unsigned long count = 1; while (1) { for ( iter1=_connections->begin(); iter1!=_connections->end(); ) { if ( (*iter1)->_errored ) { lock(); iter2 = iter1; ++iter2; delete *iter1; _connections->remove( *iter1 ); if (iter2!=_connections->end()) break; iter1 = iter2; unlock(); } } printf("There are presently %d connections (count %8d).\n",_connections->size(),count++); } } }; class mMindThreadServerListener : public mMindThread { friend class mMindServer; public: unsigned short port; unsigned long max_buffer_size; private: boost::asio::io_service* _io_service; tcp::acceptor* _acceptor; list* _connections; mMindServerHandlerClient* _new_connection; public: mMindThreadServerListener(unsigned short new_port, unsigned long new_max_buffer_size) : mMindThread() { max_buffer_size = new_max_buffer_size; port = new_port; _io_service = new boost::asio::io_service(); _acceptor = new tcp::acceptor(*_io_service, tcp::endpoint(tcp::v4(), port)); _connections = new list(); } ~mMindThreadServerListener() { delete _io_service; delete _acceptor; delete _connections; } void function(void) { mMindInternal_make_new_connection(); _io_service->run(); } private: void mMindInternal_make_new_connection(void) { _new_connection = new mMindServerHandlerClient(max_buffer_size,*_io_service); _acceptor->async_accept( _new_connection->_socket, boost::bind( &mMindThreadServerListener::mMindInternal_handle_accept, this, _new_connection, boost::asio::placeholders::error ) ); } void mMindInternal_handle_accept(mMindServerHandlerClient* new_connection, const boost::system::error_code& error) { if (error) { new_connection->_errored = true; return; } else { new_connection->mMindInternal_start(); } _connections->push_front(new_connection); } }; class mMindServer { private: mMindThreadGroup* _threads; mMindThreadServerListener* _thread_listener; mMindThreadConnectionPruner* _thread_connection_pruner; public: mMindServer(unsigned short new_port, unsigned long new_max_buffer_size) { _threads = new mMindThreadGroup(); _thread_listener = new mMindThreadServerListener(new_port,new_max_buffer_size); _thread_listener->initialize(); _thread_connection_pruner = new mMindThreadConnectionPruner(_thread_listener->_connections); _thread_connection_pruner->initialize(); _threads->add_thread(_thread_listener); _threads->add_thread(_thread_connection_pruner); } ~mMindServer() { delete _threads; delete _thread_listener; delete _thread_connection_pruner; } void start(void) { _threads->start_all(); } };