#pragma warning (disable: 4267) #include "stdafx.h" #include #include #include #include #include #include typedef boost::asio::ssl::stream ssl_socket; class session { public: session(boost::asio::io_service& io_service, boost::asio::ssl::context& context) : socket_(io_service, context) { } ssl_socket::lowest_layer_type& socket() { return socket_.lowest_layer(); } void start() { socket_.async_handshake(boost::asio::ssl::stream_base::server, boost::bind(&session::handle_handshake, this, boost::asio::placeholders::error)); } void handle_handshake(const boost::asio::error& error) { if (!error) { socket_.async_read_some(boost::asio::buffer(data_, 4), boost::bind(&session::handle_read_header, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } else { delete this; } } void handle_read_header(const boost::asio::error& error, size_t bytes_transferred) { if (!error && bytes_transferred == 4) { size_t size; memcpy(&size, data_, sizeof size); // size of the incoming string _buffer.resize(size); std::cout << "Message Header Read, incoming message size is " << size << std::endl; boost::asio::async_read(socket_, boost::asio::buffer(&_buffer[0], _buffer.size()), boost::bind(&session::handle_read_data, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } else { delete this; } } void handle_read_data(const boost::asio::error& error, size_t bytes_transferred) { if (!error) { std::cout << "Received size " << _buffer.size() << ": " << _buffer.substr(0, _buffer.size() > 60 ? 60 : _buffer.size()) << std::endl; char dataSize[20]; sprintf(dataSize, "%d", _buffer.size()); _buffer = "Received "; _buffer += dataSize; _buffer += " bytes"; boost::asio::async_write(socket_, boost::asio::buffer(_buffer), boost::bind(&session::handle_write, this, boost::asio::placeholders::error)); } else { delete this; } } void handle_write(const boost::asio::error& error) { if (!error) { if (rand() % 3 == 0) { static const char * randommsg = "This is a random message."; int len = strlen(randommsg); std::cout << "Writing out a random message of size " << len << std::endl; //boost::asio::write(socket_, boost::asio::buffer(&len, sizeof len)); boost::asio::write(socket_, boost::asio::buffer(randommsg, len)); } socket_.async_read_some(boost::asio::buffer(data_, 4), boost::bind(&session::handle_read_header, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } else { delete this; } } private: ssl_socket socket_; enum { max_length = 1024 }; char data_[max_length]; std::string _buffer; }; class server { public: server(boost::asio::io_service& io_service, unsigned short port) : io_service_(io_service), port_(port), _acceptor(io_service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)), context_(io_service, boost::asio::ssl::context::sslv23), _threads(1) { context_.set_options( boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::single_dh_use); context_.use_certificate_chain_file("server.pem"); context_.use_private_key_file("server2.pem", boost::asio::ssl::context::pem); context_.use_tmp_dh_file("dh512.pem"); } void handle_accept(session* new_session, const boost::asio::error& error) { if (!error) { new_session->start(); new_session = new session(io_service_, context_); _acceptor.async_accept(new_session->socket(), boost::bind(&server::handle_accept, this, new_session, boost::asio::placeholders::error)); } else if (error == boost::asio::error::connection_aborted) { _acceptor.async_accept(new_session->socket(), boost::bind(&server::handle_accept, this, new_session, boost::asio::placeholders::error)); } else { delete new_session; } } void threadEntry() { session* new_session = new session(io_service_, context_); _acceptor.async_accept(new_session->socket(), boost::bind(&server::handle_accept, this, new_session, boost::asio::placeholders::error)); io_service_.run(); } // run logic void run() { // create endpoint (todo: pull from manager) boost::asio::ip::tcp::endpoint ep(boost::asio::ip::tcp::v4(), port_); // open, bind, and listen to endpoint _acceptor.open(ep.protocol()); _acceptor.bind(ep); _acceptor.listen(); // create a thread pool typedef boost::shared_ptr< boost::thread > threadPtr; std::vector< threadPtr > threadPool; // create our threads for (size_t i = 0; i < _threads; ++i) { // now run the demuxer as thread per this async accept threadPool.push_back( threadPtr(new boost::thread( boost::bind(threadEntry, this) ))); } // wait on threads to end for (size_t i = 0; i < _threads; ++i) { threadPool[i]->join(); } } private: boost::asio::io_service& io_service_; boost::asio::ip::tcp::acceptor _acceptor; boost::asio::ssl::context context_; unsigned short port_; int _threads; }; int servermain(int argc, char* argv[]) { try { if (argc != 2) { std::cerr << "Usage: server \n"; return 1; } boost::asio::io_service io_service; using namespace std; // For atoi. server s(io_service, atoi(argv[1])); std::cout << "Server is accepting connections on port " << argv[1] << std::endl; //io_service.run(); s.run(); } catch (boost::asio::error& e) { std::cerr << e << "\n"; } catch (std::exception& e) { std::cerr << "Exception: " << e.what() << "\n"; } return 0; } int _tmain(int argc, _TCHAR* argv[]) { return servermain(argc, argv); }