socks5_option.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. /*
  2. * Copyright (c) 2017-2023 zhllxt
  3. *
  4. * author : zhllxt
  5. * email : 37792738@qq.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. #ifndef __ASIO2_SOCKS5_OPTION_HPP__
  11. #define __ASIO2_SOCKS5_OPTION_HPP__
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. #pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <array>
  16. #include <vector>
  17. #include <asio2/component/socks/socks5_core.hpp>
  18. namespace asio2::socks5::detail
  19. {
  20. template<class derived_t, method m>
  21. class method_field
  22. {
  23. };
  24. template<class derived_t>
  25. class method_field<derived_t, method::password>
  26. {
  27. public:
  28. method_field() = default;
  29. method_field(method_field&&) noexcept = default;
  30. method_field(method_field const&) = default;
  31. method_field& operator=(method_field&&) noexcept = default;
  32. method_field& operator=(method_field const&) = default;
  33. method_field(std::string username, std::string password)
  34. : username_(std::move(username))
  35. , password_(std::move(password))
  36. {
  37. ASIO2_ASSERT(username_.size() <= std::size_t(0xff) && password_.size() <= std::size_t(0xff));
  38. }
  39. inline derived_t& set_username(std::string v)
  40. {
  41. username_ = std::move(v);
  42. ASIO2_ASSERT(username_.size() <= std::size_t(0xff));
  43. return static_cast<derived_t&>(*this);
  44. }
  45. inline derived_t& set_password(std::string v)
  46. {
  47. password_ = std::move(v);
  48. ASIO2_ASSERT(password_.size() <= std::size_t(0xff));
  49. return static_cast<derived_t&>(*this);
  50. }
  51. inline derived_t& username(std::string v)
  52. {
  53. return this->set_username(std::move(v));
  54. }
  55. inline derived_t& password(std::string v)
  56. {
  57. return this->set_password(std::move(v));
  58. }
  59. inline std::string& username() noexcept { return username_; }
  60. inline std::string& password() noexcept { return password_; }
  61. inline std::string const& username() const noexcept { return username_; }
  62. inline std::string const& password() const noexcept { return password_; }
  63. inline std::string& get_username() noexcept { return username_; }
  64. inline std::string& get_password() noexcept { return password_; }
  65. inline std::string const& get_username() const noexcept { return username_; }
  66. inline std::string const& get_password() const noexcept { return password_; }
  67. protected:
  68. std::string username_{};
  69. std::string password_{};
  70. };
  71. template<class T, class = void>
  72. struct has_member_username : std::false_type {};
  73. template<class T>
  74. struct has_member_username<T, std::void_t<decltype(std::declval<std::decay_t<T>>().username())>> : std::true_type {};
  75. template<class T, class = void>
  76. struct has_member_password : std::false_type {};
  77. template<class T>
  78. struct has_member_password<T, std::void_t<decltype(std::declval<std::decay_t<T>>().password())>> : std::true_type {};
  79. }
  80. namespace asio2::socks5
  81. {
  82. class options;
  83. struct option_base {};
  84. template<method... ms>
  85. class option : public socks5::option_base, public socks5::detail::method_field<option<ms...>, ms>...
  86. {
  87. friend class options;
  88. protected:
  89. // vs2017 15.9.31 not supported
  90. //std::enable_if_t<((!std::is_base_of_v<socks5::option_base, asio2::detail::remove_cvref_t<Args>>) && ...)
  91. template<class... Args>
  92. constexpr static bool not_options() noexcept
  93. {
  94. return ((!std::is_base_of_v<socks5::option_base, asio2::detail::remove_cvref_t<Args>>) && ...);
  95. }
  96. public:
  97. option() = default;
  98. option(option&&) noexcept = default;
  99. option(option const&) = default;
  100. option& operator=(option&&) noexcept = default;
  101. option& operator=(option const&) = default;
  102. // constructor sfinae
  103. template<class... Args, std::enable_if_t<not_options<Args...>(), int> = 0>
  104. explicit option(Args&&... args) : option(
  105. std::conditional_t<option<ms...>::has_password_method(),
  106. std::integral_constant<int, asio2::detail::to_underlying(method::password)>,
  107. std::integral_constant<int, asio2::detail::to_underlying(method::anonymous)>>{}
  108. , std::forward<Args>(args)...)
  109. {
  110. }
  111. template<class String1, class String2, std::enable_if_t<
  112. !std::is_base_of_v<socks5::option_base, asio2::detail::remove_cvref_t<String1>> &&
  113. !std::is_base_of_v<socks5::option_base, asio2::detail::remove_cvref_t<String2>>, int> = 0>
  114. explicit option(
  115. std::integral_constant<int, asio2::detail::to_underlying(method::anonymous)>,
  116. String1&& proxy_host, String2&& proxy_port)
  117. : host_(asio2::detail::to_string(std::forward<String1>(proxy_host)))
  118. , port_(asio2::detail::to_string(std::forward<String2>(proxy_port)))
  119. {
  120. }
  121. template<class String1, class String2, class String3, class String4, std::enable_if_t<
  122. !std::is_base_of_v<socks5::option_base, asio2::detail::remove_cvref_t<String1>> &&
  123. !std::is_base_of_v<socks5::option_base, asio2::detail::remove_cvref_t<String2>> &&
  124. !std::is_base_of_v<socks5::option_base, asio2::detail::remove_cvref_t<String3>> &&
  125. !std::is_base_of_v<socks5::option_base, asio2::detail::remove_cvref_t<String4>>, int> = 0>
  126. explicit option(
  127. std::integral_constant<int, asio2::detail::to_underlying(method::password)>,
  128. String1&& proxy_host, String2&& proxy_port, String3&& username, String4&& password)
  129. : host_(asio2::detail::to_string(std::forward<String1>(proxy_host)))
  130. , port_(asio2::detail::to_string(std::forward<String2>(proxy_port)))
  131. {
  132. this->username(asio2::detail::to_string(std::forward<String3>(username)));
  133. this->password(asio2::detail::to_string(std::forward<String4>(password)));
  134. }
  135. template<class String3, class String4, std::enable_if_t<
  136. !std::is_base_of_v<socks5::option_base, asio2::detail::remove_cvref_t<String3>> &&
  137. !std::is_base_of_v<socks5::option_base, asio2::detail::remove_cvref_t<String4>>, int> = 0>
  138. explicit option(
  139. std::integral_constant<int, asio2::detail::to_underlying(method::password)>,
  140. String3&& username, String4&& password)
  141. {
  142. this->username(asio2::detail::to_string(std::forward<String3>(username)));
  143. this->password(asio2::detail::to_string(std::forward<String4>(password)));
  144. }
  145. inline option& set_host(std::string proxy_host)
  146. {
  147. host_ = std::move(proxy_host);
  148. return (*this);
  149. }
  150. template<class StrOrInt>
  151. inline option& set_port(StrOrInt&& proxy_port)
  152. {
  153. port_ = asio2::detail::to_string(std::forward<StrOrInt>(proxy_port));
  154. return (*this);
  155. }
  156. inline option& host(std::string proxy_host)
  157. {
  158. return this->set_host(std::move(proxy_host));
  159. }
  160. template<class StrOrInt>
  161. inline option& port(StrOrInt&& proxy_port)
  162. {
  163. return this->set_port(std::forward<StrOrInt>(proxy_port));
  164. }
  165. inline std::string& host() noexcept { return host_; }
  166. inline std::string& port() noexcept { return port_; }
  167. inline std::string const& host() const noexcept { return host_; }
  168. inline std::string const& port() const noexcept { return port_; }
  169. inline std::string& get_host() noexcept { return host_; }
  170. inline std::string& get_port() noexcept { return port_; }
  171. inline std::string const& get_host() const noexcept { return host_; }
  172. inline std::string const& get_port() const noexcept { return port_; }
  173. // vs2017 15.9.31 not supported
  174. //constexpr static bool has_password_method = ((ms == method::password) || ...);
  175. template<typename = void>
  176. constexpr static bool has_password_method() noexcept
  177. {
  178. return ((ms == method::password) || ...);
  179. }
  180. inline std::array<method, sizeof...(ms)> get_methods() noexcept
  181. {
  182. return methods_;
  183. }
  184. inline std::array<method, sizeof...(ms)> methods() noexcept
  185. {
  186. return methods_;
  187. }
  188. constexpr auto get_methods_count() const noexcept
  189. {
  190. return methods_.size();
  191. }
  192. constexpr auto methods_count() const noexcept
  193. {
  194. return methods_.size();
  195. }
  196. inline socks5::command command() const noexcept { return cmd_; }
  197. inline socks5::command get_command() const noexcept { return cmd_; }
  198. inline option& command(socks5::command cmd) noexcept { cmd_ = cmd; return (*this); }
  199. inline option& set_command(socks5::command cmd) noexcept { cmd_ = cmd; return (*this); }
  200. protected:
  201. std::array<method, sizeof...(ms)> methods_{ ms... };
  202. std::string host_{};
  203. std::string port_{};
  204. socks5::command cmd_{};
  205. };
  206. class options : public socks5::option_base
  207. {
  208. protected:
  209. template<class S5Opt>
  210. inline std::string socks5_opt_username(S5Opt&& s5opt) noexcept
  211. {
  212. if constexpr (socks5::detail::has_member_username<S5Opt>::value)
  213. return s5opt.username();
  214. else
  215. return "";
  216. }
  217. template<class S5Opt>
  218. inline std::string socks5_opt_password(S5Opt&& s5opt) noexcept
  219. {
  220. if constexpr (socks5::detail::has_member_password<S5Opt>::value)
  221. return s5opt.password();
  222. else
  223. return "";
  224. }
  225. public:
  226. options() = default;
  227. ~options() = default;
  228. options(options&&) noexcept = default;
  229. options(options const&) = default;
  230. options& operator=(options&&) noexcept = default;
  231. options& operator=(options const&) = default;
  232. template<class String1, class String2>
  233. options(String1&& host, String2&& port)
  234. {
  235. methods_.emplace_back(socks5::method::anonymous);
  236. host_ = asio2::detail::to_string(std::forward<String1>(host));
  237. port_ = asio2::detail::to_string(std::forward<String2>(port));
  238. }
  239. template<class String1, class String2, class String3, class String4>
  240. options(String1&& host, String2&& port, String3&& username, String4&& password)
  241. {
  242. methods_.emplace_back(socks5::method::anonymous);
  243. methods_.emplace_back(socks5::method::password);
  244. host_ = asio2::detail::to_string(std::forward<String1>(host));
  245. port_ = asio2::detail::to_string(std::forward<String2>(port));
  246. username_ = asio2::detail::to_string(std::forward<String3>(username));
  247. password_ = asio2::detail::to_string(std::forward<String4>(password));
  248. }
  249. template<method... ms>
  250. options& operator=(const socks5::option<ms...>& opt)
  251. {
  252. methods_.clear();
  253. for (socks5::method m : opt.methods_)
  254. {
  255. methods_.emplace_back(m);
  256. }
  257. cmd_ = opt.cmd_;
  258. host_ = opt.host_;
  259. port_ = opt.port_;
  260. username_ = socks5_opt_username(opt);
  261. password_ = socks5_opt_password(opt);
  262. return *this;
  263. }
  264. template<method... ms>
  265. options(const socks5::option<ms...>& opt)
  266. {
  267. *this = opt;
  268. }
  269. template<class... Ms>
  270. inline options& set_methods(Ms... ms)
  271. {
  272. methods_.clear();
  273. (methods_.emplace_back(ms), ...);
  274. return *this;
  275. }
  276. inline std::vector<socks5::method>& get_methods() noexcept { return methods_; }
  277. inline std::vector<socks5::method>& methods() noexcept { return methods_; }
  278. inline const std::vector<socks5::method>& get_methods() const noexcept { return methods_; }
  279. inline const std::vector<socks5::method>& methods() const noexcept { return methods_; }
  280. inline std::size_t get_methods_count() const noexcept { return methods_.size(); }
  281. inline std::size_t methods_count() const noexcept { return methods_.size(); }
  282. inline bool has_password_method() const noexcept
  283. {
  284. for (socks5::method m : methods_)
  285. {
  286. if (m == socks5::method::password)
  287. return true;
  288. }
  289. return false;
  290. }
  291. inline options& set_command(socks5::command cmd)
  292. {
  293. cmd_ = cmd;
  294. return *this;
  295. }
  296. inline options& command(socks5::command cmd)
  297. {
  298. cmd_ = cmd;
  299. return *this;
  300. }
  301. inline socks5::command get_command() { return cmd_; }
  302. inline socks5::command command() { return cmd_; }
  303. template<class String1>
  304. inline options& set_host(String1&& host)
  305. {
  306. host_ = asio2::detail::to_string(std::forward<String1>(host));
  307. return (*this);
  308. }
  309. template<class String1>
  310. inline options& host(String1&& host)
  311. {
  312. return set_host(std::forward<String1>(host));
  313. }
  314. template<class StrOrInt>
  315. inline options& set_port(StrOrInt&& port)
  316. {
  317. port_ = asio2::detail::to_string(std::forward<StrOrInt>(port));
  318. return (*this);
  319. }
  320. template<class StrOrInt>
  321. inline options& port(StrOrInt&& port)
  322. {
  323. return set_port(std::forward<StrOrInt>(port));
  324. }
  325. template<class String1>
  326. inline options& set_username(String1&& username)
  327. {
  328. username_ = asio2::detail::to_string(std::forward<String1>(username));
  329. return (*this);
  330. }
  331. template<class String1>
  332. inline options& username(String1&& username)
  333. {
  334. return set_username(std::forward<String1>(username));
  335. }
  336. template<class String1>
  337. inline options& set_password(String1&& password)
  338. {
  339. password_ = asio2::detail::to_string(std::forward<String1>(password));
  340. return (*this);
  341. }
  342. template<class String1>
  343. inline options& password(String1&& password)
  344. {
  345. return set_password(std::forward<String1>(password));
  346. }
  347. inline std::string& get_host() noexcept { return host_;}
  348. inline std::string& get_port() noexcept { return port_;}
  349. inline std::string& get_username() noexcept { return username_; }
  350. inline std::string& get_password() noexcept { return password_; }
  351. inline std::string& host() noexcept { return host_; }
  352. inline std::string& port() noexcept { return port_; }
  353. inline std::string& username() noexcept { return username_; }
  354. inline std::string& password() noexcept { return password_; }
  355. inline const std::string& get_host() const noexcept { return host_;}
  356. inline const std::string& get_port() const noexcept { return port_;}
  357. inline const std::string& get_username() const noexcept { return username_; }
  358. inline const std::string& get_password() const noexcept { return password_; }
  359. inline const std::string& host() const noexcept { return host_; }
  360. inline const std::string& port() const noexcept { return port_; }
  361. inline const std::string& username() const noexcept { return username_; }
  362. inline const std::string& password() const noexcept { return password_; }
  363. inline options& set_auth_callback(std::function<bool(const std::string&, const std::string&)> auth_cb)
  364. {
  365. auth_cb_ = std::move(auth_cb);
  366. return *this;
  367. }
  368. inline std::function<bool(const std::string&, const std::string&)>& get_auth_callback() noexcept
  369. {
  370. return auth_cb_;
  371. }
  372. inline const std::function<bool(const std::string&, const std::string&)>& get_auth_callback() const noexcept
  373. {
  374. return auth_cb_;
  375. }
  376. protected:
  377. std::vector<socks5::method> methods_;
  378. std::string host_{};
  379. std::string port_{};
  380. std::string username_{};
  381. std::string password_{};
  382. socks5::command cmd_{};
  383. std::function<bool(const std::string&, const std::string&)> auth_cb_;
  384. };
  385. }
  386. #endif // !__ASIO2_SOCKS5_OPTION_HPP__