Advertisement
ReallyMatrix

Untitled

May 25th, 2020
1,100
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.41 KB | None | 0 0
  1. #pragma once
  2. #include "utilities.hpp"
  3. #include <boost/asio.hpp>
  4. #include <boost/beast.hpp>
  5. #include <optional>
  6.  
  7. namespace server {
  8. namespace net = boost::asio;
  9. namespace beast = boost::beast;
  10. namespace http = beast::http;
  11. namespace csock = net::detail::socket_ops;
  12.  
  13. using net::ip::tcp;
  14.  
  15. class custom_timed_socket_t {
  16.   net::io_context &io_context_;
  17.   net::ip::basic_resolver_results<tcp> &resolves_;
  18.   int http_status_code_ = -1;
  19.   bool data_read_error_ = false;
  20.  
  21. public:
  22.   bool data_read_error() const { return data_read_error_; }
  23.   int http_status_code() const { return http_status_code_; }
  24.  
  25.   custom_timed_socket_t(net::io_context &io_context,
  26.                         net::ip::basic_resolver_results<tcp> &resolves)
  27.       : io_context_{io_context}, resolves_{resolves} {}
  28.  
  29.   std::optional<std::string> get(std::string const &url,
  30.                                  int const connect_timeout_sec,
  31.                                  int const read_timeout_sec,
  32.                                  boost::system::error_code &ec) {
  33.  
  34.     utilities::uri const more_ip_uri_{url};
  35.     net::ip::basic_resolver_results<tcp>::iterator resolver_iter{};
  36.     bool is_ipv4 = true;
  37.     if (resolves_.empty()) {
  38.       net::ip::tcp::resolver resolver{io_context_};
  39.       resolves_ =
  40.           resolver.resolve(more_ip_uri_.host(), more_ip_uri_.protocol());
  41.     }
  42.     resolver_iter =
  43.         std::find_if(resolves_.begin(), resolves_.end(), [](auto const &ep) {
  44.           return ep.endpoint().address().is_v4();
  45.         });
  46.     is_ipv4 = resolver_iter != resolves_.end();
  47.     if (!is_ipv4) {
  48.       resolver_iter = std::find_if(
  49.           resolves_.begin(), resolves_.end(),
  50.           [](net::ip::basic_resolver_entry<net::ip::tcp> const &ep) {
  51.             return ep.endpoint().address().is_v6();
  52.           });
  53.       if (resolver_iter == resolves_.end()) {
  54.         return std::nullopt;
  55.       }
  56.     }
  57.  
  58.     tcp::socket http_tcp_socket(net::make_strand(io_context_));
  59.  
  60.     if (is_ipv4) {
  61.       http_tcp_socket.open(net::ip::tcp::v4(), ec);
  62.     } else {
  63.       http_tcp_socket.open(net::ip::tcp::v6(), ec);
  64.     }
  65.     if (ec) {
  66.       return std::nullopt;
  67.     }
  68.     ec = {};
  69.     auto socket_nhandle = http_tcp_socket.native_handle();
  70.     if (!http_tcp_socket.native_non_blocking())
  71.       http_tcp_socket.native_non_blocking(true, ec);
  72.  
  73.     if (ec) {
  74.       return std::nullopt;
  75.     }
  76.  
  77.     http_tcp_socket.connect(*resolver_iter);
  78.  
  79.     ec = {};
  80.     int const connect_time_ms = connect_timeout_sec * 1'000;
  81.    auto result = csock::poll_connect(socket_nhandle, connect_time_ms, ec);
  82.    if (ec || result < 0) {
  83.      return std::nullopt;
  84.    }
  85.    int connect_error = 0;
  86.    std::size_t connect_error_len = sizeof(connect_error);
  87.    auto const get_sock_result =
  88.        csock::getsockopt(socket_nhandle, 0, SOL_SOCKET, SO_ERROR,
  89.                          &connect_error, &connect_error_len, ec);
  90.    if (get_sock_result != 0 || ec) {
  91.      return std::nullopt;
  92.    }
  93.    ec = {};
  94.    if (http_tcp_socket.native_non_blocking()) {
  95.      http_tcp_socket.native_non_blocking(false, ec);
  96.    }
  97.    if (ec) {
  98.      return std::nullopt;
  99.    }
  100.  
  101.    http::request<http::empty_body> http_request{};
  102.    http_request.method(http::verb::get);
  103.    http_request.target(more_ip_uri_.target());
  104.    http_request.version(11);
  105.    http_request.set(http::field::host, more_ip_uri_.host());
  106.    http_request.set(http::field::user_agent, utilities::get_random_agent());
  107.  
  108.    http::write(http_tcp_socket, http_request, ec);
  109.    beast::flat_buffer buffer{};
  110.    http::response<http::string_body> server_response{};
  111.  
  112.    if (!http_tcp_socket.native_non_blocking())
  113.      http_tcp_socket.native_non_blocking(true, ec);
  114.  
  115.    if (ec) {
  116.      return std::nullopt;
  117.    }
  118.  
  119.    http::read(http_tcp_socket, buffer, server_response, ec);
  120.    ec = {};
  121.  
  122.    int const read_time_ms = read_timeout_sec * 1'000;
  123.     result = csock::poll_read(socket_nhandle, 0, read_time_ms, ec);
  124.     if (ec || result < 0) {
  125.       // would like to know if the error obtained is due to timeout on read
  126.       data_read_error_ = true;
  127.       return std::nullopt;
  128.     }
  129.  
  130.     ec = {};
  131.     if (http_tcp_socket.native_non_blocking())
  132.       http_tcp_socket.native_non_blocking(false, ec);
  133.  
  134.     http_tcp_socket.shutdown(tcp::socket::shutdown_both, ec);
  135.     http_status_code_ = server_response.result_int();
  136.     return server_response.body();
  137.   }
  138. };
  139.  
  140. } // namespace server
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement