#include #include #include "session.h" session::session(boost::asio::ip::tcp::socket socket, boost::asio::io_service &io_service, std::string hostname, std::string port) : socket_(std::move(socket)), io_service_{io_service}, resolver_{io_service}, server_{io_service}, timer_{io_service}, host{hostname}, port{port} { server_sent = 0; } void session::start(void) { std::cout << "session" << std::endl; auto self(shared_from_this()); // read_buffer.reserve(1024); // do_write("Welcome!\n"); do_read(); } session::~session() { std::cout << "~session destructed" << std::endl; } void session::parse_auth(void) { // how many nulls should I be seeing? // \0user\0pass\0terminal/SPEED\0 // Maybe in the future I'll care about parsing this out. I don't right now. // Ok, yes I do! If I don't have a proper rlogin value here, it isn't going // to work when I try to connect to the rlogin server. if (rlogin_auth.size() > 10) rlogin_name = rlogin_auth.c_str() + 1; else rlogin_name = "?"; } void session::on_connect(const boost::system::error_code error) { // We've connected to the server! WOOT WOOT! if (!error) { std::cout << "Connected to server!" << std::endl; do_write("Connected...\n\r"); connected = true; if (rlogin_auth[0] != 0) { // Ok, the rlogin information was junk -- do_write("Let me make up some fake rlogin data for you...\n\r"); char temp[] = "\0test\0test\0terminal/9600\0"; std::string tmp(temp, sizeof(temp)); server_write(tmp); } else { server_write(rlogin_auth); } server_read(); } else { // TODO: std::string output = "Failed to connect : "; output += host; output += " : "; output += port; output += "\n\r"; do_write(output); std::cout << "Failed to connect to server." << std::endl; std::cout << "SHUTDOWN..." << std::endl; socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both); } } void session::dispatch_line(std::string line) { // Does this have \n\r still on it? I don't want them. std::cout << "SL: " << line << std::endl; // is echo on? if so: } void session::process_lines(void) { // break server_prompt into lines and send/process one by one. size_t pos; while ((pos = server_prompt.find("\n\r")) != std::string::npos) { // line std::string line = server_prompt.substr(0, pos + 2); server_prompt = server_prompt.substr(pos + 2); // Remove \n\r for dispatching std::string part = line.substr(0, pos); if (server_sent != 0) { line = line.substr(server_sent); server_sent = 0; }; // display on? do_write(line); dispatch_line(part); } // display on? if (server_sent != 0) { std::string part = server_prompt.substr(server_sent); do_write(part); server_sent = server_prompt.size(); } else { do_write(server_prompt); server_sent = server_prompt.size(); } // server_sent is the # of chars we've already sent of this. } void session::server_read(void) { auto self(shared_from_this()); boost::asio::async_read( server_, boost::asio::buffer(server_buffer, sizeof(server_buffer) - 1), boost::asio::transfer_at_least(1), [this, self](boost::system::error_code ec, std::size_t length) { if (!ec) { server_buffer[length] = 0; server_prompt.append(server_buffer, length); process_lines(); /* if (length) { // std::cout << length << std::endl; std::cout << "S: " << server_buffer << std::endl; do_write(server_buffer); } */ server_read(); } else { std::cout << "S: read_failed: connection closed" << std::endl; socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both); // socket_.async_shutdown(boost::bind(&session::on_shutdown, this, // boost::asio::placeholders::error)); } }); } void session::on_resolve( const boost::system::error_code error, const boost::asio::ip::tcp::resolver::results_type results) { // auto self(shared_from_this()); if (!error) { // Take the first endpoint. boost::asio::ip::tcp::endpoint const &endpoint = *results; server_.async_connect(endpoint, boost::bind(&session::on_connect, this, boost::asio::placeholders::error)); } else { // TO DO: std::string output = "Unable to resolve: "; output += host; output += "\n\r"; do_write(output); std::cout << "Unable to resolve?" << std::endl; std::cout << "SHUTDOWN ..." << std::endl; socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both); } } void session::do_read(void) { auto self(shared_from_this()); boost::asio::async_read( // why can't I async_read_some here? socket_, boost::asio::buffer(read_buffer, sizeof(read_buffer) - 1), boost::asio::transfer_at_least(1), [this, self](boost::system::error_code ec, std::size_t length) { if (!ec) { read_buffer[length] = 0; if (rlogin_auth.empty()) { // first read should be rlogin information rlogin_auth.assign(read_buffer, length); // parse authentication information parse_auth(); do_write(std::string(1, 0)); do_write("Welcome, "); do_write(rlogin_name); do_write("\n\r"); // Activate the connection to the server /* // this fails, and I'm not sure why. I've used code like this before. resolver_.async_resolve( host, port, std::bind( &session::on_resolve, this, _1, _2)); */ // This example shows using boost::bind, which WORKS. // https://stackoverflow.com/questions/6025471/bind-resolve-handler-to-resolver-async-resolve-using-boostasio resolver_.async_resolve( host, port, boost::bind(&session::on_resolve, this, boost::asio::placeholders::error, boost::asio::placeholders::iterator)); } else if (length) { // std::cout << length << std::endl; server_write(read_buffer); std::cout << "C: " << read_buffer << std::endl; // do_write(output); } do_read(); } else { std::cout << "C: read_failed: connection closed" << std::endl; if (connected) server_.shutdown(boost::asio::ip::tcp::socket::shutdown_both); // server_.async_shutdown(boost::bind(&session::on_shutdown, this, // boost::asio::placeholders::error)); } }); } void session::do_write(std::string message) { auto self(shared_from_this()); boost::asio::async_write( socket_, boost::asio::buffer(message), [this, self](boost::system::error_code ec, std::size_t /*length*/) { if (!ec) { } else { std::cout << "write failed? closed?" << std::endl; server_.shutdown(boost::asio::ip::tcp::socket::shutdown_both); // server_.async_shutdown(boost::bind(&session::on_shutdown, this, // boost::asio::placeholders::error)); } }); } void session::server_write(std::string message) { auto self(shared_from_this()); boost::asio::async_write( server_, boost::asio::buffer(message), [this, self](boost::system::error_code ec, std::size_t /*length*/) { if (!ec) { } else { std::cout << "write failed? closed?" << std::endl; socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both); // socket_.async_shutdown(boost::bind(&session::on_shutdown, this, // boost::asio::placeholders::error)); } }); } void session::on_shutdown(boost::system::error_code ec) { std::cout << "shutdown." << std::endl; }