socket_cp.hpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  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_SOCKET_COMPONENT_HPP__
  11. #define __ASIO2_SOCKET_COMPONENT_HPP__
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. #pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <string>
  16. #include <asio2/external/asio.hpp>
  17. namespace asio2::detail
  18. {
  19. template<class derived_t, class args_t>
  20. class socket_cp
  21. {
  22. public:
  23. using socket_type = std::remove_cv_t<std::remove_reference_t<typename args_t::socket_t>>;
  24. /**
  25. * @brief constructor
  26. * @throws maybe throw exception "Too many open files" (exception code : 24)
  27. * asio::error::no_descriptors - Too many open files
  28. */
  29. explicit socket_cp(asio::io_context& ioc) : socket_(std::make_shared<socket_type>(ioc))
  30. {
  31. }
  32. /**
  33. * @brief constructor
  34. * @li for udp session
  35. */
  36. explicit socket_cp(std::shared_ptr<typename args_t::socket_t> ptr) : socket_(std::move(ptr))
  37. {
  38. }
  39. /**
  40. * @brief destructor
  41. */
  42. ~socket_cp()
  43. {
  44. }
  45. public:
  46. /**
  47. * @brief get the socket object reference
  48. */
  49. inline socket_type & socket() noexcept
  50. {
  51. return *(this->socket_);
  52. }
  53. /**
  54. * @brief get the socket object reference
  55. */
  56. inline const socket_type & socket() const noexcept
  57. {
  58. return *(this->socket_);
  59. }
  60. /**
  61. * @brief get the stream object reference
  62. */
  63. inline socket_type & stream() noexcept
  64. {
  65. return *(this->socket_);
  66. }
  67. /**
  68. * @brief get the stream object reference
  69. */
  70. inline const socket_type & stream() const noexcept
  71. {
  72. return *(this->socket_);
  73. }
  74. /**
  75. * @brief get the local address, same as get_local_address
  76. */
  77. inline std::string local_address() const noexcept
  78. {
  79. return this->get_local_address();
  80. }
  81. /**
  82. * @brief get the local address
  83. */
  84. inline std::string get_local_address() const noexcept
  85. {
  86. clear_last_error();
  87. try
  88. {
  89. return this->socket_->lowest_layer().local_endpoint().address().to_string();
  90. }
  91. catch (const system_error& e)
  92. {
  93. set_last_error(e);
  94. }
  95. return std::string();
  96. }
  97. /**
  98. * @brief get the local port, same as get_local_port
  99. */
  100. inline unsigned short local_port() const noexcept
  101. {
  102. return this->get_local_port();
  103. }
  104. /**
  105. * @brief get the local port
  106. */
  107. inline unsigned short get_local_port() const noexcept
  108. {
  109. return this->socket_->lowest_layer().local_endpoint(get_last_error()).port();
  110. }
  111. /**
  112. * @brief get the remote address, same as get_remote_address
  113. */
  114. inline std::string remote_address() const noexcept
  115. {
  116. return this->get_remote_address();
  117. }
  118. /**
  119. * @brief get the remote address
  120. */
  121. inline std::string get_remote_address() const noexcept
  122. {
  123. clear_last_error();
  124. error_code ec{};
  125. try
  126. {
  127. return this->socket_->lowest_layer().remote_endpoint().address().to_string();
  128. }
  129. catch (const system_error& e)
  130. {
  131. ec = e.code();
  132. }
  133. try
  134. {
  135. asio::ip::address addr = this->remote_endpoint_.address();
  136. if (!addr.is_unspecified())
  137. {
  138. return addr.to_string();
  139. }
  140. }
  141. catch (const system_error&)
  142. {
  143. }
  144. set_last_error(ec);
  145. return std::string();
  146. }
  147. /**
  148. * @brief get the remote port, same as get_remote_port
  149. */
  150. inline unsigned short remote_port() const noexcept
  151. {
  152. return this->get_remote_port();
  153. }
  154. /**
  155. * @brief get the remote port
  156. */
  157. inline unsigned short get_remote_port() const noexcept
  158. {
  159. clear_last_error();
  160. error_code ec{};
  161. try
  162. {
  163. return this->socket_->lowest_layer().remote_endpoint().port();
  164. }
  165. catch (const system_error& e)
  166. {
  167. ec = e.code();
  168. }
  169. try
  170. {
  171. return this->remote_endpoint_.port();
  172. }
  173. catch (const system_error&)
  174. {
  175. }
  176. set_last_error(ec);
  177. return 0;
  178. }
  179. public:
  180. /**
  181. * @brief Implements the SOL_SOCKET/SO_SNDBUF socket option.
  182. */
  183. inline derived_t& set_sndbuf_size(int val) noexcept
  184. {
  185. this->socket_->lowest_layer().set_option(asio::socket_base::send_buffer_size(val), get_last_error());
  186. return (static_cast<derived_t&>(*this));
  187. }
  188. /**
  189. * @brief Implements the SOL_SOCKET/SO_SNDBUF socket option.
  190. */
  191. inline int get_sndbuf_size() const noexcept
  192. {
  193. asio::socket_base::send_buffer_size option{};
  194. this->socket_->lowest_layer().get_option(option, get_last_error());
  195. return option.value();
  196. }
  197. /**
  198. * @brief Implements the SOL_SOCKET/SO_RCVBUF socket option.
  199. */
  200. inline derived_t& set_rcvbuf_size(int val) noexcept
  201. {
  202. this->socket_->lowest_layer().set_option(asio::socket_base::receive_buffer_size(val), get_last_error());
  203. return (static_cast<derived_t&>(*this));
  204. }
  205. /**
  206. * @brief Implements the SOL_SOCKET/SO_RCVBUF socket option.
  207. */
  208. inline int get_rcvbuf_size() const noexcept
  209. {
  210. asio::socket_base::receive_buffer_size option{};
  211. this->socket_->lowest_layer().get_option(option, get_last_error());
  212. return option.value();
  213. }
  214. /**
  215. * @brief Implements the SOL_SOCKET/SO_KEEPALIVE socket option. same as set_keep_alive
  216. */
  217. inline derived_t & keep_alive(bool val) noexcept
  218. {
  219. return this->set_keep_alive(val);
  220. }
  221. /**
  222. * @brief Implements the SOL_SOCKET/SO_KEEPALIVE socket option.
  223. */
  224. inline derived_t& set_keep_alive(bool val) noexcept
  225. {
  226. this->socket_->lowest_layer().set_option(asio::socket_base::keep_alive(val), get_last_error());
  227. return (static_cast<derived_t&>(*this));
  228. }
  229. /**
  230. * @brief Implements the SOL_SOCKET/SO_KEEPALIVE socket option.
  231. */
  232. inline bool is_keep_alive() const noexcept
  233. {
  234. asio::socket_base::keep_alive option{};
  235. this->socket_->lowest_layer().get_option(option, get_last_error());
  236. return option.value();
  237. }
  238. /**
  239. * @brief Implements the SOL_SOCKET/SO_REUSEADDR socket option. same as set_reuse_address
  240. */
  241. inline derived_t & reuse_address(bool val) noexcept
  242. {
  243. return this->set_reuse_address(val);
  244. }
  245. /**
  246. * @brief Implements the SOL_SOCKET/SO_REUSEADDR socket option.
  247. */
  248. inline derived_t& set_reuse_address(bool val) noexcept
  249. {
  250. this->socket_->lowest_layer().set_option(asio::socket_base::reuse_address(val), get_last_error());
  251. return (static_cast<derived_t&>(*this));
  252. }
  253. /**
  254. * @brief Implements the SOL_SOCKET/SO_REUSEADDR socket option.
  255. */
  256. inline bool is_reuse_address() const noexcept
  257. {
  258. asio::socket_base::reuse_address option{};
  259. this->socket_->lowest_layer().get_option(option, get_last_error());
  260. return option.value();
  261. }
  262. /**
  263. * @brief Implements the TCP_NODELAY socket option. same as set_no_delay.
  264. * If it's not a tcp socket, do nothing
  265. */
  266. inline derived_t & no_delay(bool val) noexcept
  267. {
  268. return this->set_no_delay(val);
  269. }
  270. /**
  271. * @brief Implements the TCP_NODELAY socket option.
  272. * If it's not a tcp socket, do nothing
  273. */
  274. inline derived_t& set_no_delay(bool val) noexcept
  275. {
  276. this->socket_->lowest_layer().set_option(asio::ip::tcp::no_delay(val), get_last_error());
  277. return (static_cast<derived_t&>(*this));
  278. }
  279. /**
  280. * @brief Implements the TCP_NODELAY socket option.
  281. */
  282. inline bool is_no_delay() const noexcept
  283. {
  284. asio::ip::tcp::no_delay option{};
  285. this->socket_->lowest_layer().get_option(option, get_last_error());
  286. return option.value();
  287. }
  288. /**
  289. * @brief Implements the SO_LINGER socket option.
  290. * set_linger(true, 0) - RST will be sent instead of FIN/ACK/FIN/ACK
  291. * @param enable - option on/off
  292. * @param timeout - linger time
  293. */
  294. inline derived_t& set_linger(bool enable, int timeout) noexcept
  295. {
  296. this->socket_->lowest_layer().set_option(asio::socket_base::linger(enable, timeout), get_last_error());
  297. return (static_cast<derived_t&>(*this));
  298. }
  299. /**
  300. * @brief Get the SO_LINGER socket option.
  301. */
  302. inline asio::socket_base::linger get_linger() const noexcept
  303. {
  304. asio::socket_base::linger option{};
  305. this->socket_->lowest_layer().get_option(option, get_last_error());
  306. return option;
  307. }
  308. protected:
  309. /// socket
  310. /// 20230802 change this member variable from "typename args_t::socket_t socket_;"
  311. /// to "std::shared_ptr<typename args_t::socket_t> socket_;", why? beacuse the
  312. /// socket shoule be destroyed before the io_context destroyed, otherwise maybe
  313. /// cause crash, so we use a shared_ptr to manually manage the lifecycle of socket.
  314. std::shared_ptr<typename args_t::socket_t> socket_;
  315. /// the call of remote_endpoint() maybe failed when the remote socket is closed,
  316. /// even if local socket is not closed, so we use this variable to ensure the
  317. /// call of remote_endpoint() must be successed.
  318. typename socket_type::endpoint_type remote_endpoint_{};
  319. };
  320. }
  321. #endif // !__ASIO2_SOCKET_COMPONENT_HPP__