tcp_client.hpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. // MIT License
  2. //
  3. // Copyright (c) 2016-2017 Simon Ninon <simon.ninon@gmail.com>
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in all
  13. // copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  21. // SOFTWARE.
  22. #pragma once
  23. #include <atomic>
  24. #include <cstdint>
  25. #include <mutex>
  26. #include <queue>
  27. #include <string>
  28. #include <tacopie/network/io_service.hpp>
  29. #include <tacopie/network/tcp_socket.hpp>
  30. #include <tacopie/utils/typedefs.hpp>
  31. namespace tacopie {
  32. //!
  33. //! tacopie::tcp_server is the class providing TCP Client features.
  34. //! The tcp_client works entirely asynchronously
  35. //!
  36. class tcp_client {
  37. public:
  38. //! ctor & dtor
  39. tcp_client(void);
  40. ~tcp_client(void);
  41. //!
  42. //! custom ctor
  43. //! build socket from existing socket
  44. //!
  45. //! \param socket tcp_socket instance to be used for building the client (socket will be moved)
  46. //!
  47. explicit tcp_client(tcp_socket&& socket);
  48. //! copy ctor
  49. tcp_client(const tcp_client&) = delete;
  50. //! assignment operator
  51. tcp_client& operator=(const tcp_client&) = delete;
  52. public:
  53. //!
  54. //! comparison operator
  55. //!
  56. //! \return true when the underlying sockets are the same (same file descriptor and socket type).
  57. //!
  58. bool operator==(const tcp_client& rhs) const;
  59. //!
  60. //! comparison operator
  61. //!
  62. //! \return true when the underlying sockets are different (different file descriptor or socket type).
  63. //!
  64. bool operator!=(const tcp_client& rhs) const;
  65. public:
  66. //!
  67. //! \return the hostname associated with the underlying socket.
  68. //!
  69. const std::string& get_host(void) const;
  70. //!
  71. //! \return the port associated with the underlying socket.
  72. //!
  73. std::uint32_t get_port(void) const;
  74. public:
  75. //!
  76. //! Connect the socket to the remote server.
  77. //!
  78. //! \param host Hostname of the target server
  79. //! \param port Port of the target server
  80. //! \param timeout_msecs maximum time to connect (will block until connect succeed or timeout expire). 0 will block undefinitely. If timeout expires, connection fails
  81. //!
  82. void connect(const std::string& host, std::uint32_t port, std::uint32_t timeout_msecs = 0);
  83. //!
  84. //! Disconnect the tcp_client if it was currently connected.
  85. //!
  86. //! \param wait_for_removal When sets to true, disconnect blocks until the underlying TCP client has been effectively removed from the io_service and that all the underlying callbacks have completed.
  87. //!
  88. void disconnect(bool wait_for_removal = false);
  89. //!
  90. //! \return whether the client is currently connected or not
  91. //!
  92. bool is_connected(void) const;
  93. private:
  94. //!
  95. //! Call the user-defined disconnection handler
  96. //!
  97. void call_disconnection_handler(void);
  98. public:
  99. //!
  100. //! structure to store read requests result
  101. //! * success: Whether the read operation has succeeded or not. If false, the client has been disconnected
  102. //! * buffer: Vector containing the read bytes
  103. //!
  104. struct read_result {
  105. //!
  106. //! whether the operation succeeeded or not
  107. //!
  108. bool success;
  109. //!
  110. //! read bytes
  111. //!
  112. std::vector<char> buffer;
  113. };
  114. //!
  115. //! structure to store write requests result
  116. //! * success: Whether the write operation has succeeded or not. If false, the client has been disconnected
  117. //! * size: Number of bytes written
  118. //!
  119. struct write_result {
  120. //!
  121. //! whether the operation succeeeded or not
  122. //!
  123. bool success;
  124. //!
  125. //! number of bytes written
  126. //!
  127. std::size_t size;
  128. };
  129. public:
  130. //!
  131. //! callback to be called on async read completion
  132. //! takes the read_result as a parameter
  133. //!
  134. typedef std::function<void(read_result&)> async_read_callback_t;
  135. //!
  136. //! callback to be called on async write completion
  137. //! takes the write_result as a parameter
  138. //!
  139. typedef std::function<void(write_result&)> async_write_callback_t;
  140. public:
  141. //!
  142. //! structure to store read requests information
  143. //! * size: Number of bytes to read
  144. //! * async_read_callback: Callback to be called on a read operation completion, even though the operation read less bytes than requested.
  145. //!
  146. struct read_request {
  147. //!
  148. //! number of bytes to read
  149. //!
  150. std::size_t size;
  151. //!
  152. //! callback to be executed on read operation completion
  153. //!
  154. async_read_callback_t async_read_callback;
  155. };
  156. //!
  157. //! structure to store write requests information
  158. //! * buffer: Bytes to be written
  159. //! * async_write_callback: Callback to be called on a write operation completion, even though the operation wrote less bytes than requested.
  160. //!
  161. struct write_request {
  162. //!
  163. //! bytes to write
  164. //!
  165. std::vector<char> buffer;
  166. //!
  167. //! callback to be executed on write operation completion
  168. //!
  169. async_write_callback_t async_write_callback;
  170. };
  171. public:
  172. //!
  173. //! async read operation
  174. //!
  175. //! \param request read request information
  176. //!
  177. void async_read(const read_request& request);
  178. //!
  179. //! async write operation
  180. //!
  181. //! \param request write request information
  182. //!
  183. void async_write(const write_request& request);
  184. public:
  185. //!
  186. //! \return underlying tcp_socket (non-const version)
  187. //!
  188. tacopie::tcp_socket& get_socket(void);
  189. //!
  190. //! \return underlying tcp_socket (const version)
  191. //!
  192. const tacopie::tcp_socket& get_socket(void) const;
  193. public:
  194. //!
  195. //! \return io service monitoring this tcp connection
  196. //!
  197. const std::shared_ptr<tacopie::io_service>& get_io_service(void) const;
  198. public:
  199. //!
  200. //! disconnection handle
  201. //! called whenever a disconnection occured
  202. //!
  203. //!
  204. typedef std::function<void()> disconnection_handler_t;
  205. //!
  206. //! set on disconnection handler
  207. //!
  208. //! \param disconnection_handler the handler to be called on disconnection
  209. //!
  210. void set_on_disconnection_handler(const disconnection_handler_t& disconnection_handler);
  211. private:
  212. //!
  213. //! io service read callback
  214. //! called by the io service whenever the socket is readable
  215. //!
  216. //! \param fd file description of the socket for which the read is available
  217. //!
  218. void on_read_available(fd_t fd);
  219. //!
  220. //! io service write callback
  221. //! called by the io service whenever the socket is writable
  222. //!
  223. //! \param fd file description of the socket for which the write is available
  224. //!
  225. void on_write_available(fd_t fd);
  226. private:
  227. //!
  228. //! Clear pending read requests (basically empty the queue of read requests)
  229. //!
  230. void clear_read_requests(void);
  231. //!
  232. //! Clear pending write requests (basically empty the queue of write requests)
  233. //!
  234. void clear_write_requests(void);
  235. private:
  236. //!
  237. //! process read operations when available
  238. //! basically called whenever on_read_available is called and try to read from the socket
  239. //! handle possible case of failure and fill in the result
  240. //!
  241. //! \param result result of the read operation
  242. //! \return the callback to be executed (set in the read request) on read completion (may be null)
  243. //!
  244. async_read_callback_t process_read(read_result& result);
  245. //!
  246. //! process write operations when available
  247. //! basically called whenever on_write_available is called and try to write to the socket
  248. //! handle possible case of failure and fill in the result
  249. //!
  250. //! \param result result of the write operation
  251. //! \return the callback to be executed (set in the write request) on read completion (may be null)
  252. //!
  253. async_write_callback_t process_write(write_result& result);
  254. private:
  255. //!
  256. //! store io_service
  257. //! prevent deletion of io_service before the tcp_client itself
  258. //!
  259. std::shared_ptr<io_service> m_io_service;
  260. //!
  261. //! client socket
  262. //!
  263. tacopie::tcp_socket m_socket;
  264. //!
  265. //! whether the client is currently connected or not
  266. //!
  267. std::atomic<bool> m_is_connected = ATOMIC_VAR_INIT(false);
  268. //!
  269. //! read requests
  270. //!
  271. std::queue<read_request> m_read_requests;
  272. //!
  273. //! write requests
  274. //!
  275. std::queue<write_request> m_write_requests;
  276. //!
  277. //! read requests thread safety
  278. //!
  279. std::mutex m_read_requests_mtx;
  280. //!
  281. //! write requests thread safety
  282. //!
  283. std::mutex m_write_requests_mtx;
  284. //!
  285. //! disconnection handler
  286. //!
  287. disconnection_handler_t m_disconnection_handler;
  288. };
  289. } // namespace tacopie