client.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. //
  2. // client.cpp
  3. // ~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. #include <cstdlib>
  11. #include <cstring>
  12. #include <functional>
  13. #include <iostream>
  14. #include <boost/asio.hpp>
  15. #include <boost/asio/ssl.hpp>
  16. using boost::asio::ip::tcp;
  17. using std::placeholders::_1;
  18. using std::placeholders::_2;
  19. enum { max_length = 1024 };
  20. class client
  21. {
  22. public:
  23. client(boost::asio::io_context& io_context,
  24. boost::asio::ssl::context& context,
  25. const tcp::resolver::results_type& endpoints)
  26. : socket_(io_context, context)
  27. {
  28. socket_.set_verify_mode(boost::asio::ssl::verify_peer);
  29. socket_.set_verify_callback(
  30. std::bind(&client::verify_certificate, this, _1, _2));
  31. connect(endpoints);
  32. }
  33. private:
  34. bool verify_certificate(bool preverified,
  35. boost::asio::ssl::verify_context& ctx)
  36. {
  37. // The verify callback can be used to check whether the certificate that is
  38. // being presented is valid for the peer. For example, RFC 2818 describes
  39. // the steps involved in doing this for HTTPS. Consult the OpenSSL
  40. // documentation for more details. Note that the callback is called once
  41. // for each certificate in the certificate chain, starting from the root
  42. // certificate authority.
  43. // In this example we will simply print the certificate's subject name.
  44. char subject_name[256];
  45. X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
  46. X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256);
  47. std::cout << "Verifying " << subject_name << "\n";
  48. return preverified;
  49. }
  50. void connect(const tcp::resolver::results_type& endpoints)
  51. {
  52. boost::asio::async_connect(socket_.lowest_layer(), endpoints,
  53. [this](const boost::system::error_code& error,
  54. const tcp::endpoint& /*endpoint*/)
  55. {
  56. if (!error)
  57. {
  58. handshake();
  59. }
  60. else
  61. {
  62. std::cout << "Connect failed: " << error.message() << "\n";
  63. }
  64. });
  65. }
  66. void handshake()
  67. {
  68. socket_.async_handshake(boost::asio::ssl::stream_base::client,
  69. [this](const boost::system::error_code& error)
  70. {
  71. if (!error)
  72. {
  73. send_request();
  74. }
  75. else
  76. {
  77. std::cout << "Handshake failed: " << error.message() << "\n";
  78. }
  79. });
  80. }
  81. void send_request()
  82. {
  83. std::cout << "Enter message: ";
  84. std::cin.getline(request_, max_length);
  85. size_t request_length = std::strlen(request_);
  86. boost::asio::async_write(socket_,
  87. boost::asio::buffer(request_, request_length),
  88. [this](const boost::system::error_code& error, std::size_t length)
  89. {
  90. if (!error)
  91. {
  92. receive_response(length);
  93. }
  94. else
  95. {
  96. std::cout << "Write failed: " << error.message() << "\n";
  97. }
  98. });
  99. }
  100. void receive_response(std::size_t length)
  101. {
  102. boost::asio::async_read(socket_,
  103. boost::asio::buffer(reply_, length),
  104. [this](const boost::system::error_code& error, std::size_t length)
  105. {
  106. if (!error)
  107. {
  108. std::cout << "Reply: ";
  109. std::cout.write(reply_, length);
  110. std::cout << "\n";
  111. }
  112. else
  113. {
  114. std::cout << "Read failed: " << error.message() << "\n";
  115. }
  116. });
  117. }
  118. boost::asio::ssl::stream<tcp::socket> socket_;
  119. char request_[max_length];
  120. char reply_[max_length];
  121. };
  122. int main(int argc, char* argv[])
  123. {
  124. try
  125. {
  126. if (argc != 3)
  127. {
  128. std::cerr << "Usage: client <host> <port>\n";
  129. return 1;
  130. }
  131. boost::asio::io_context io_context;
  132. tcp::resolver resolver(io_context);
  133. auto endpoints = resolver.resolve(argv[1], argv[2]);
  134. boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
  135. ctx.load_verify_file("ca.pem");
  136. client c(io_context, ctx, endpoints);
  137. io_context.run();
  138. }
  139. catch (std::exception& e)
  140. {
  141. std::cerr << "Exception: " << e.what() << "\n";
  142. }
  143. return 0;
  144. }