session.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. #include <boost/bind.hpp>
  2. #include <iostream>
  3. #include "session.h"
  4. session::session(boost::asio::ip::tcp::socket socket,
  5. boost::asio::io_service &io_service, std::string hostname,
  6. std::string port)
  7. : socket_(std::move(socket)),
  8. io_service_{io_service}, resolver_{io_service}, server_{io_service},
  9. timer_{io_service}, host{hostname}, port{port} {
  10. server_sent = 0;
  11. }
  12. void session::start(void) {
  13. std::cout << "session" << std::endl;
  14. auto self(shared_from_this());
  15. // read_buffer.reserve(1024);
  16. // do_write("Welcome!\n");
  17. do_read();
  18. }
  19. session::~session() { std::cout << "~session destructed" << std::endl; }
  20. void session::parse_auth(void) {
  21. // how many nulls should I be seeing?
  22. // \0user\0pass\0terminal/SPEED\0
  23. // Maybe in the future I'll care about parsing this out. I don't right now.
  24. // Ok, yes I do! If I don't have a proper rlogin value here, it isn't going
  25. // to work when I try to connect to the rlogin server.
  26. if (rlogin_auth.size() > 10)
  27. rlogin_name = rlogin_auth.c_str() + 1;
  28. else
  29. rlogin_name = "?";
  30. }
  31. void session::on_connect(const boost::system::error_code error) {
  32. // We've connected to the server! WOOT WOOT!
  33. if (!error) {
  34. std::cout << "Connected to server!" << std::endl;
  35. do_write("Connected...\n\r");
  36. connected = true;
  37. if (rlogin_auth[0] != 0) {
  38. // Ok, the rlogin information was junk --
  39. do_write("Let me make up some fake rlogin data for you...\n\r");
  40. char temp[] = "\0test\0test\0terminal/9600\0";
  41. std::string tmp(temp, sizeof(temp));
  42. server_write(tmp);
  43. } else {
  44. server_write(rlogin_auth);
  45. }
  46. server_read();
  47. } else {
  48. // TODO:
  49. std::string output = "Failed to connect : ";
  50. output += host;
  51. output += " : ";
  52. output += port;
  53. output += "\n\r";
  54. do_write(output);
  55. std::cout << "Failed to connect to server." << std::endl;
  56. std::cout << "SHUTDOWN..." << std::endl;
  57. socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
  58. }
  59. }
  60. void session::dispatch_line(std::string line) {
  61. // Does this have \n\r still on it? I don't want them.
  62. std::cout << "SL: " << line << std::endl;
  63. // is echo on? if so:
  64. }
  65. void session::process_lines(void) {
  66. // break server_prompt into lines and send/process one by one.
  67. size_t pos;
  68. while ((pos = server_prompt.find("\n\r")) != std::string::npos) {
  69. // line
  70. std::string line = server_prompt.substr(0, pos + 2);
  71. server_prompt = server_prompt.substr(pos + 2);
  72. // Remove \n\r for dispatching
  73. std::string part = line.substr(0, pos);
  74. if (server_sent != 0) {
  75. line = line.substr(server_sent);
  76. server_sent = 0;
  77. };
  78. // display on?
  79. do_write(line);
  80. dispatch_line(part);
  81. }
  82. // display on?
  83. if (server_sent != 0) {
  84. std::string part = server_prompt.substr(server_sent);
  85. do_write(part);
  86. server_sent = server_prompt.size();
  87. } else {
  88. do_write(server_prompt);
  89. server_sent = server_prompt.size();
  90. }
  91. // server_sent is the # of chars we've already sent of this.
  92. }
  93. void session::server_read(void) {
  94. auto self(shared_from_this());
  95. boost::asio::async_read(
  96. server_, boost::asio::buffer(server_buffer, sizeof(server_buffer) - 1),
  97. boost::asio::transfer_at_least(1),
  98. [this, self](boost::system::error_code ec, std::size_t length) {
  99. if (!ec) {
  100. server_buffer[length] = 0;
  101. server_prompt.append(server_buffer, length);
  102. process_lines();
  103. /*
  104. if (length) {
  105. // std::cout << length << std::endl;
  106. std::cout << "S: " << server_buffer << std::endl;
  107. do_write(server_buffer);
  108. }
  109. */
  110. server_read();
  111. } else {
  112. std::cout << "S: read_failed: connection closed" << std::endl;
  113. socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
  114. // socket_.async_shutdown(boost::bind(&session::on_shutdown, this,
  115. // boost::asio::placeholders::error));
  116. }
  117. });
  118. }
  119. void session::on_resolve(
  120. const boost::system::error_code error,
  121. const boost::asio::ip::tcp::resolver::results_type results) {
  122. //
  123. auto self(shared_from_this());
  124. if (!error) {
  125. // Take the first endpoint.
  126. boost::asio::ip::tcp::endpoint const &endpoint = *results;
  127. server_.async_connect(endpoint,
  128. boost::bind(&session::on_connect, this,
  129. boost::asio::placeholders::error));
  130. } else {
  131. // TO DO:
  132. std::string output = "Unable to resolve: ";
  133. output += host;
  134. output += "\n\r";
  135. do_write(output);
  136. std::cout << "Unable to resolve?" << std::endl;
  137. std::cout << "SHUTDOWN ..." << std::endl;
  138. socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
  139. }
  140. }
  141. void session::do_read(void) {
  142. auto self(shared_from_this());
  143. boost::asio::async_read( // why can't I async_read_some here?
  144. socket_, boost::asio::buffer(read_buffer, sizeof(read_buffer) - 1),
  145. boost::asio::transfer_at_least(1),
  146. [this, self](boost::system::error_code ec, std::size_t length) {
  147. if (!ec) {
  148. read_buffer[length] = 0;
  149. if (rlogin_auth.empty()) {
  150. // first read should be rlogin information
  151. rlogin_auth.assign(read_buffer, length);
  152. // parse authentication information
  153. parse_auth();
  154. do_write(std::string(1, 0));
  155. do_write("Welcome, ");
  156. do_write(rlogin_name);
  157. do_write("\n\r");
  158. // Activate the connection to the server
  159. /* // this fails, and I'm not sure why. I've used code like this
  160. before. resolver_.async_resolve( host, port, std::bind(
  161. &session::on_resolve, this, _1, _2)); */
  162. // This example shows using boost::bind, which WORKS.
  163. // https://stackoverflow.com/questions/6025471/bind-resolve-handler-to-resolver-async-resolve-using-boostasio
  164. resolver_.async_resolve(
  165. host, port,
  166. boost::bind(&session::on_resolve, this,
  167. boost::asio::placeholders::error,
  168. boost::asio::placeholders::iterator));
  169. } else if (length) {
  170. // std::cout << length << std::endl;
  171. server_write(read_buffer);
  172. std::cout << "C: " << read_buffer << std::endl;
  173. // do_write(output);
  174. }
  175. do_read();
  176. } else {
  177. std::cout << "C: read_failed: connection closed" << std::endl;
  178. if (connected)
  179. server_.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
  180. // server_.async_shutdown(boost::bind(&session::on_shutdown, this,
  181. // boost::asio::placeholders::error));
  182. }
  183. });
  184. }
  185. void session::do_write(std::string message) {
  186. auto self(shared_from_this());
  187. boost::asio::async_write(
  188. socket_, boost::asio::buffer(message),
  189. [this, self](boost::system::error_code ec, std::size_t /*length*/) {
  190. if (!ec) {
  191. } else {
  192. std::cout << "write failed? closed?" << std::endl;
  193. server_.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
  194. // server_.async_shutdown(boost::bind(&session::on_shutdown, this,
  195. // boost::asio::placeholders::error));
  196. }
  197. });
  198. }
  199. void session::server_write(std::string message) {
  200. auto self(shared_from_this());
  201. boost::asio::async_write(
  202. server_, boost::asio::buffer(message),
  203. [this, self](boost::system::error_code ec, std::size_t /*length*/) {
  204. if (!ec) {
  205. } else {
  206. std::cout << "write failed? closed?" << std::endl;
  207. socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
  208. // socket_.async_shutdown(boost::bind(&session::on_shutdown, this,
  209. // boost::asio::placeholders::error));
  210. }
  211. });
  212. }
  213. void session::on_shutdown(boost::system::error_code ec) {
  214. std::cout << "shutdown." << std::endl;
  215. }