/* * Copyright (c) 2017-2023 zhllxt * * author : zhllxt * email : 37792738@qq.com * * Distributed under the Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #ifndef __ASIO2_SOCKS5_OPTION_HPP__ #define __ASIO2_SOCKS5_OPTION_HPP__ #if defined(_MSC_VER) && (_MSC_VER >= 1200) #pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include #include #include namespace asio2::socks5::detail { template class method_field { }; template class method_field { public: method_field() = default; method_field(method_field&&) noexcept = default; method_field(method_field const&) = default; method_field& operator=(method_field&&) noexcept = default; method_field& operator=(method_field const&) = default; method_field(std::string username, std::string password) : username_(std::move(username)) , password_(std::move(password)) { ASIO2_ASSERT(username_.size() <= std::size_t(0xff) && password_.size() <= std::size_t(0xff)); } inline derived_t& set_username(std::string v) { username_ = std::move(v); ASIO2_ASSERT(username_.size() <= std::size_t(0xff)); return static_cast(*this); } inline derived_t& set_password(std::string v) { password_ = std::move(v); ASIO2_ASSERT(password_.size() <= std::size_t(0xff)); return static_cast(*this); } inline derived_t& username(std::string v) { return this->set_username(std::move(v)); } inline derived_t& password(std::string v) { return this->set_password(std::move(v)); } inline std::string& username() noexcept { return username_; } inline std::string& password() noexcept { return password_; } inline std::string const& username() const noexcept { return username_; } inline std::string const& password() const noexcept { return password_; } inline std::string& get_username() noexcept { return username_; } inline std::string& get_password() noexcept { return password_; } inline std::string const& get_username() const noexcept { return username_; } inline std::string const& get_password() const noexcept { return password_; } protected: std::string username_{}; std::string password_{}; }; template struct has_member_username : std::false_type {}; template struct has_member_username>().username())>> : std::true_type {}; template struct has_member_password : std::false_type {}; template struct has_member_password>().password())>> : std::true_type {}; } namespace asio2::socks5 { class options; struct option_base {}; template class option : public socks5::option_base, public socks5::detail::method_field, ms>... { friend class options; protected: // vs2017 15.9.31 not supported //std::enable_if_t<((!std::is_base_of_v>) && ...) template constexpr static bool not_options() noexcept { return ((!std::is_base_of_v>) && ...); } public: option() = default; option(option&&) noexcept = default; option(option const&) = default; option& operator=(option&&) noexcept = default; option& operator=(option const&) = default; // constructor sfinae template(), int> = 0> explicit option(Args&&... args) : option( std::conditional_t::has_password_method(), std::integral_constant, std::integral_constant>{} , std::forward(args)...) { } template> && !std::is_base_of_v>, int> = 0> explicit option( std::integral_constant, String1&& proxy_host, String2&& proxy_port) : host_(asio2::detail::to_string(std::forward(proxy_host))) , port_(asio2::detail::to_string(std::forward(proxy_port))) { } template> && !std::is_base_of_v> && !std::is_base_of_v> && !std::is_base_of_v>, int> = 0> explicit option( std::integral_constant, String1&& proxy_host, String2&& proxy_port, String3&& username, String4&& password) : host_(asio2::detail::to_string(std::forward(proxy_host))) , port_(asio2::detail::to_string(std::forward(proxy_port))) { this->username(asio2::detail::to_string(std::forward(username))); this->password(asio2::detail::to_string(std::forward(password))); } template> && !std::is_base_of_v>, int> = 0> explicit option( std::integral_constant, String3&& username, String4&& password) { this->username(asio2::detail::to_string(std::forward(username))); this->password(asio2::detail::to_string(std::forward(password))); } inline option& set_host(std::string proxy_host) { host_ = std::move(proxy_host); return (*this); } template inline option& set_port(StrOrInt&& proxy_port) { port_ = asio2::detail::to_string(std::forward(proxy_port)); return (*this); } inline option& host(std::string proxy_host) { return this->set_host(std::move(proxy_host)); } template inline option& port(StrOrInt&& proxy_port) { return this->set_port(std::forward(proxy_port)); } inline std::string& host() noexcept { return host_; } inline std::string& port() noexcept { return port_; } inline std::string const& host() const noexcept { return host_; } inline std::string const& port() const noexcept { return port_; } inline std::string& get_host() noexcept { return host_; } inline std::string& get_port() noexcept { return port_; } inline std::string const& get_host() const noexcept { return host_; } inline std::string const& get_port() const noexcept { return port_; } // vs2017 15.9.31 not supported //constexpr static bool has_password_method = ((ms == method::password) || ...); template constexpr static bool has_password_method() noexcept { return ((ms == method::password) || ...); } inline std::array get_methods() noexcept { return methods_; } inline std::array methods() noexcept { return methods_; } constexpr auto get_methods_count() const noexcept { return methods_.size(); } constexpr auto methods_count() const noexcept { return methods_.size(); } inline socks5::command command() const noexcept { return cmd_; } inline socks5::command get_command() const noexcept { return cmd_; } inline option& command(socks5::command cmd) noexcept { cmd_ = cmd; return (*this); } inline option& set_command(socks5::command cmd) noexcept { cmd_ = cmd; return (*this); } protected: std::array methods_{ ms... }; std::string host_{}; std::string port_{}; socks5::command cmd_{}; }; class options : public socks5::option_base { protected: template inline std::string socks5_opt_username(S5Opt&& s5opt) noexcept { if constexpr (socks5::detail::has_member_username::value) return s5opt.username(); else return ""; } template inline std::string socks5_opt_password(S5Opt&& s5opt) noexcept { if constexpr (socks5::detail::has_member_password::value) return s5opt.password(); else return ""; } public: options() = default; ~options() = default; options(options&&) noexcept = default; options(options const&) = default; options& operator=(options&&) noexcept = default; options& operator=(options const&) = default; template options(String1&& host, String2&& port) { methods_.emplace_back(socks5::method::anonymous); host_ = asio2::detail::to_string(std::forward(host)); port_ = asio2::detail::to_string(std::forward(port)); } template options(String1&& host, String2&& port, String3&& username, String4&& password) { methods_.emplace_back(socks5::method::anonymous); methods_.emplace_back(socks5::method::password); host_ = asio2::detail::to_string(std::forward(host)); port_ = asio2::detail::to_string(std::forward(port)); username_ = asio2::detail::to_string(std::forward(username)); password_ = asio2::detail::to_string(std::forward(password)); } template options& operator=(const socks5::option& opt) { methods_.clear(); for (socks5::method m : opt.methods_) { methods_.emplace_back(m); } cmd_ = opt.cmd_; host_ = opt.host_; port_ = opt.port_; username_ = socks5_opt_username(opt); password_ = socks5_opt_password(opt); return *this; } template options(const socks5::option& opt) { *this = opt; } template inline options& set_methods(Ms... ms) { methods_.clear(); (methods_.emplace_back(ms), ...); return *this; } inline std::vector& get_methods() noexcept { return methods_; } inline std::vector& methods() noexcept { return methods_; } inline const std::vector& get_methods() const noexcept { return methods_; } inline const std::vector& methods() const noexcept { return methods_; } inline std::size_t get_methods_count() const noexcept { return methods_.size(); } inline std::size_t methods_count() const noexcept { return methods_.size(); } inline bool has_password_method() const noexcept { for (socks5::method m : methods_) { if (m == socks5::method::password) return true; } return false; } inline options& set_command(socks5::command cmd) { cmd_ = cmd; return *this; } inline options& command(socks5::command cmd) { cmd_ = cmd; return *this; } inline socks5::command get_command() { return cmd_; } inline socks5::command command() { return cmd_; } template inline options& set_host(String1&& host) { host_ = asio2::detail::to_string(std::forward(host)); return (*this); } template inline options& host(String1&& host) { return set_host(std::forward(host)); } template inline options& set_port(StrOrInt&& port) { port_ = asio2::detail::to_string(std::forward(port)); return (*this); } template inline options& port(StrOrInt&& port) { return set_port(std::forward(port)); } template inline options& set_username(String1&& username) { username_ = asio2::detail::to_string(std::forward(username)); return (*this); } template inline options& username(String1&& username) { return set_username(std::forward(username)); } template inline options& set_password(String1&& password) { password_ = asio2::detail::to_string(std::forward(password)); return (*this); } template inline options& password(String1&& password) { return set_password(std::forward(password)); } inline std::string& get_host() noexcept { return host_;} inline std::string& get_port() noexcept { return port_;} inline std::string& get_username() noexcept { return username_; } inline std::string& get_password() noexcept { return password_; } inline std::string& host() noexcept { return host_; } inline std::string& port() noexcept { return port_; } inline std::string& username() noexcept { return username_; } inline std::string& password() noexcept { return password_; } inline const std::string& get_host() const noexcept { return host_;} inline const std::string& get_port() const noexcept { return port_;} inline const std::string& get_username() const noexcept { return username_; } inline const std::string& get_password() const noexcept { return password_; } inline const std::string& host() const noexcept { return host_; } inline const std::string& port() const noexcept { return port_; } inline const std::string& username() const noexcept { return username_; } inline const std::string& password() const noexcept { return password_; } inline options& set_auth_callback(std::function auth_cb) { auth_cb_ = std::move(auth_cb); return *this; } inline std::function& get_auth_callback() noexcept { return auth_cb_; } inline const std::function& get_auth_callback() const noexcept { return auth_cb_; } protected: std::vector methods_; std::string host_{}; std::string port_{}; std::string username_{}; std::string password_{}; socks5::command cmd_{}; std::function auth_cb_; }; } #endif // !__ASIO2_SOCKS5_OPTION_HPP__