| 1 | #pragma once
|
|---|
| 2 |
|
|---|
| 3 | #include <boost/shared_ptr.hpp>
|
|---|
| 4 | #include <boost/asio.hpp>
|
|---|
| 5 |
|
|---|
| 6 | #include <socket/socket_helpers.hpp>
|
|---|
| 7 |
|
|---|
| 8 | #include <nsca/nsca_packet.hpp>
|
|---|
| 9 | #include <nsca/nsca_enrypt.hpp>
|
|---|
| 10 |
|
|---|
| 11 | using boost::asio::ip::tcp;
|
|---|
| 12 |
|
|---|
| 13 | namespace nsca {
|
|---|
| 14 |
|
|---|
| 15 | class socket : public boost::noncopyable {
|
|---|
| 16 | private:
|
|---|
| 17 | boost::shared_ptr<tcp::socket> socket_;
|
|---|
| 18 | boost::asio::io_service &io_service_;
|
|---|
| 19 | nsca_encrypt crypt_inst;
|
|---|
| 20 | int time;
|
|---|
| 21 | public:
|
|---|
| 22 | typedef boost::asio::basic_socket<tcp,boost::asio::stream_socket_service<tcp> > basic_socket_type;
|
|---|
| 23 |
|
|---|
| 24 | public:
|
|---|
| 25 | socket(boost::asio::io_service &io_service) : io_service_(io_service), time(0) {
|
|---|
| 26 | socket_.reset(new tcp::socket(io_service_));
|
|---|
| 27 | }
|
|---|
| 28 | ~socket() {
|
|---|
| 29 | if (socket_)
|
|---|
| 30 | socket_->close();
|
|---|
| 31 | socket_.reset();
|
|---|
| 32 | }
|
|---|
| 33 |
|
|---|
| 34 | virtual void connect(std::string host, std::string port) {
|
|---|
| 35 | NSC_DEBUG_MSG(_T("Connecting to: ") + utf8::cvt<std::wstring>(host) + _T(" (") + utf8::cvt<std::wstring>(port) + _T(")"));
|
|---|
| 36 | tcp::resolver resolver(io_service_);
|
|---|
| 37 | tcp::resolver::query query(host, port);
|
|---|
| 38 |
|
|---|
| 39 | tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
|
|---|
| 40 | tcp::resolver::iterator end;
|
|---|
| 41 |
|
|---|
| 42 | boost::system::error_code error = boost::asio::error::host_not_found;
|
|---|
| 43 | while (error && endpoint_iterator != end) {
|
|---|
| 44 | tcp::resolver::endpoint_type ep = *endpoint_iterator;
|
|---|
| 45 | socket_->close();
|
|---|
| 46 | socket_->connect(*endpoint_iterator++, error);
|
|---|
| 47 | NSC_DEBUG_MSG(_T("Connected to: ") + utf8::cvt<std::wstring>(ep.address().to_string()));
|
|---|
| 48 | }
|
|---|
| 49 | if (error) {
|
|---|
| 50 | NSC_DEBUG_MSG(_T("Failed to connect to:") + utf8::to_unicode(host));
|
|---|
| 51 | throw boost::system::system_error(error);
|
|---|
| 52 | }
|
|---|
| 53 | }
|
|---|
| 54 |
|
|---|
| 55 |
|
|---|
| 56 | virtual void shutdown() {
|
|---|
| 57 | NSC_DEBUG_MSG(_T("Ending socket (gracefully)"));
|
|---|
| 58 | // Initiate graceful connection closure.
|
|---|
| 59 | boost::system::error_code ignored_ec;
|
|---|
| 60 | if (socket_)
|
|---|
| 61 | socket_->shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
|
|---|
| 62 | };
|
|---|
| 63 | virtual void close() {
|
|---|
| 64 | if (socket_)
|
|---|
| 65 | socket_->close();
|
|---|
| 66 | socket_.reset();
|
|---|
| 67 | };
|
|---|
| 68 |
|
|---|
| 69 | virtual void send_nsca(const nsca::packet &packet, const boost::posix_time::seconds timeout) {
|
|---|
| 70 | if (!socket_ || !socket_->is_open()) {
|
|---|
| 71 | NSC_LOG_ERROR_STD(_T("Socket was closed when trying to send data..."));
|
|---|
| 72 | return;
|
|---|
| 73 | }
|
|---|
| 74 | std::string buffer = crypt_inst.get_rand_buffer(packet.get_packet_length());
|
|---|
| 75 | packet.get_buffer(buffer, time);
|
|---|
| 76 | crypt_inst.encrypt_buffer(buffer);
|
|---|
| 77 | NSC_DEBUG_MSG(_T("Sending data: ") + strEx::itos(buffer.size()));
|
|---|
| 78 | write_with_timeout(buffer, timeout);
|
|---|
| 79 | }
|
|---|
| 80 | virtual bool recv_iv(std::string password, int encryption_method, boost::posix_time::seconds timeout) {
|
|---|
| 81 | if (!socket_ || !socket_->is_open()) {
|
|---|
| 82 | NSC_LOG_ERROR_STD(_T("Socket was closed when trying to read data..."));
|
|---|
| 83 | return false;
|
|---|
| 84 | }
|
|---|
| 85 | unsigned int len = nsca::length::iv::get_packet_length();
|
|---|
| 86 | std::vector<char> buf(len);
|
|---|
| 87 | if (!read_with_timeout(buf, timeout)) {
|
|---|
| 88 | NSC_LOG_ERROR_STD(_T("Failed to read IV from server (using ") + strEx::itos(encryption_method) + _T(", ") + strEx::itos(len) + _T(")."));
|
|---|
| 89 | return false;
|
|---|
| 90 | }
|
|---|
| 91 | nsca::iv_packet iv_packet(std::string(buf.begin(), buf.end()));
|
|---|
| 92 | std::string iv = iv_packet.get_iv();
|
|---|
| 93 | time = iv_packet.get_time();
|
|---|
| 94 | NSC_DEBUG_MSG(_T("Encrypting using: ") + utf8::cvt<std::wstring>(nsca::nsca_encrypt::helpers::encryption_to_string(encryption_method)) + _T(", password '") + utf8::cvt<std::wstring>(password) + _T("'"));
|
|---|
| 95 | crypt_inst.encrypt_init(password, encryption_method, iv);
|
|---|
| 96 | return true;
|
|---|
| 97 | }
|
|---|
| 98 | virtual bool read_with_timeout(std::vector<char> &buf, boost::posix_time::seconds timeout) {
|
|---|
| 99 | return socket_helpers::io::read_with_timeout(*socket_, *socket_, boost::asio::buffer(buf), timeout);
|
|---|
| 100 | }
|
|---|
| 101 | virtual void write_with_timeout(std::string &buf, boost::posix_time::seconds timeout) {
|
|---|
| 102 | socket_helpers::io::write_with_timeout(*socket_, *socket_, boost::asio::buffer(buf), timeout);
|
|---|
| 103 | }
|
|---|
| 104 | };
|
|---|
| 105 | } |
|---|