tcp_socket_unittest.cc 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. // Copyright (C) 2011, 2015 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. /// \brief Test of TCPSocket
  15. ///
  16. /// Tests the functionality of a TCPSocket by working through an open-send-
  17. /// receive-close sequence and checking that the asynchronous notifications
  18. /// work.
  19. #include <config.h>
  20. #include <string>
  21. #include <arpa/inet.h>
  22. #include <netinet/in.h>
  23. #include <sys/types.h>
  24. #include <sys/socket.h>
  25. #include <algorithm>
  26. #include <cstdlib>
  27. #include <cstddef>
  28. #include <vector>
  29. #include <gtest/gtest.h>
  30. #include <boost/bind.hpp>
  31. #include <boost/shared_ptr.hpp>
  32. #include <util/buffer.h>
  33. #include <util/io_utilities.h>
  34. #include <boost/asio.hpp>
  35. #include <asiolink/io_service.h>
  36. #include <asiolink/tcp_endpoint.h>
  37. #include <asiolink/tcp_socket.h>
  38. using namespace boost::asio;
  39. using namespace boost::asio::ip;
  40. using namespace isc::util;
  41. using namespace isc::asiolink;
  42. using namespace std;
  43. namespace {
  44. const char SERVER_ADDRESS[] = "127.0.0.1";
  45. const unsigned short SERVER_PORT = 5303;
  46. // TODO: Shouldn't we send something that is real message?
  47. const char OUTBOUND_DATA[] = "Data sent from client to server";
  48. const char INBOUND_DATA[] = "Returned data from server to client";
  49. }
  50. /// An instance of this object is passed to the asynchronous I/O functions
  51. /// and the operator() method is called when when an asynchronous I/O completes.
  52. /// The arguments to the completion callback are stored for later retrieval.
  53. class TCPCallback {
  54. public:
  55. /// \brief Operations the server is doing
  56. enum Operation {
  57. ACCEPT = 0, ///< accept() was issued
  58. OPEN = 1, /// Client connected to server
  59. READ = 2, ///< Asynchronous read completed
  60. WRITE = 3, ///< Asynchronous write completed
  61. NONE = 4 ///< "Not set" state
  62. };
  63. /// \brief Minimim size of buffers
  64. enum {
  65. MIN_SIZE = (64 * 1024 + 2) ///< 64kB + two bytes for a count
  66. };
  67. struct PrivateData {
  68. PrivateData() :
  69. error_code_(), length_(0), cumulative_(0), expected_(0), offset_(0),
  70. name_(""), queued_(NONE), called_(NONE), data_(MIN_SIZE, 0)
  71. {}
  72. boost::system::error_code error_code_; ///< Completion error code
  73. size_t length_; ///< Bytes transferred in this I/O
  74. size_t cumulative_; ///< Cumulative bytes transferred
  75. size_t expected_; ///< Expected amount of data
  76. size_t offset_; ///< Where to put data in buffer
  77. std::string name_; ///< Which of the objects this is
  78. Operation queued_; ///< Queued operation
  79. Operation called_; ///< Which callback called
  80. std::vector<uint8_t> data_; ///< Receive buffer
  81. };
  82. /// \brief Constructor
  83. ///
  84. /// Constructs the object. It also creates the data member pointed to by
  85. /// a shared pointer. When used as a callback object, this is copied as it
  86. /// is passed into the asynchronous function. This means that there are two
  87. /// objects and inspecting the one we passed in does not tell us anything.
  88. ///
  89. /// Therefore we use a boost::shared_ptr. When the object is copied, the
  90. /// shared pointer is copied, which leaves both objects pointing to the same
  91. /// data.
  92. ///
  93. /// \param which Which of the two callback objects this is
  94. TCPCallback(std::string which) : ptr_(new PrivateData())
  95. {
  96. ptr_->name_ = which;
  97. }
  98. /// \brief Destructor
  99. ///
  100. /// No code needed, destroying the shared pointer destroys the private data.
  101. virtual ~TCPCallback()
  102. {}
  103. /// \brief Client Callback Function
  104. ///
  105. /// Called when an asynchronous operation is completed by the client, this
  106. /// stores the origin of the operation in the client_called_ data member.
  107. ///
  108. /// \param ec I/O completion error code passed to callback function.
  109. /// \param length Number of bytes transferred
  110. void operator()(boost::system::error_code ec = boost::system::error_code(),
  111. size_t length = 0)
  112. {
  113. setCode(ec.value());
  114. ptr_->called_ = ptr_->queued_;
  115. ptr_->length_ = length;
  116. }
  117. /// \brief Get I/O completion error code
  118. int getCode() {
  119. return (ptr_->error_code_.value());
  120. }
  121. /// \brief Set I/O completion code
  122. ///
  123. /// \param code New value of completion code
  124. void setCode(int code) {
  125. ptr_->error_code_ = boost::system::error_code(code, boost::system::error_code().category());
  126. }
  127. /// \brief Get number of bytes transferred in I/O
  128. size_t& length() {
  129. return (ptr_->length_);
  130. }
  131. /// \brief Get cumulative number of bytes transferred in I/O
  132. size_t& cumulative() {
  133. return (ptr_->cumulative_);
  134. }
  135. /// \brief Get expected amount of data
  136. size_t& expected() {
  137. return (ptr_->expected_);
  138. }
  139. /// \brief Get offset intodData
  140. size_t& offset() {
  141. return (ptr_->offset_);
  142. }
  143. /// \brief Get data member
  144. uint8_t* data() {
  145. return (&ptr_->data_[0]);
  146. }
  147. /// \brief Get flag to say what was queued
  148. Operation& queued() {
  149. return (ptr_->queued_);
  150. }
  151. /// \brief Get flag to say when callback was called
  152. Operation& called() {
  153. return (ptr_->called_);
  154. }
  155. /// \brief Return instance of callback name
  156. std::string& name() {
  157. return (ptr_->name_);
  158. }
  159. private:
  160. boost::shared_ptr<PrivateData> ptr_; ///< Pointer to private data
  161. };
  162. // Read Server Data
  163. //
  164. // Called in the part of the test that has the client send a message to the
  165. // server, this loops until all the data has been read (synchronously) by the
  166. // server.
  167. //
  168. // "All the data read" means that the server has received a message that is
  169. // preceded by a two-byte count field and that the total amount of data received
  170. // from the remote end is equal to the value in the count field plus two bytes
  171. // for the count field itself.
  172. //
  173. // \param socket Socket on which the server is reading data
  174. // \param server_cb Structure in which server data is held.
  175. void
  176. serverRead(tcp::socket& socket, TCPCallback& server_cb) {
  177. // As we may need to read multiple times, keep a count of the cumulative
  178. // amount of data read and do successive reads into the appropriate part
  179. // of the buffer.
  180. //
  181. // Note that there are no checks for buffer overflow - this is a test
  182. // program and we have sized the buffer to be large enough for the test.
  183. server_cb.cumulative() = 0;
  184. bool complete = false;
  185. while (!complete) {
  186. // Read block of data and update cumulative amount of data received.
  187. server_cb.length() = socket.receive(
  188. boost::asio::buffer(server_cb.data() + server_cb.cumulative(),
  189. TCPCallback::MIN_SIZE - server_cb.cumulative()));
  190. server_cb.cumulative() += server_cb.length();
  191. // If we have read at least two bytes, we can work out how much we
  192. // should be reading.
  193. if (server_cb.cumulative() >= 2) {
  194. server_cb.expected() = readUint16(server_cb.data(), server_cb.length());
  195. if ((server_cb.expected() + 2) == server_cb.cumulative()) {
  196. // Amount of data read from socket equals the size of the
  197. // message (as indicated in the first two bytes of the message)
  198. // plus the size of the count field. Therefore we have received
  199. // all the data.
  200. complete = true;
  201. }
  202. }
  203. }
  204. }
  205. // Receive complete method should return true only if the count in the first
  206. // two bytes is equal to the size of the rest if the buffer.
  207. TEST(TCPSocket, processReceivedData) {
  208. const uint16_t PACKET_SIZE = 16382; // Amount of "real" data in the buffer
  209. IOService service; // Used to instantiate socket
  210. TCPSocket<TCPCallback> test(service); // Socket under test
  211. uint8_t inbuff[PACKET_SIZE + 2]; // Buffer to check
  212. OutputBufferPtr outbuff(new OutputBuffer(16));
  213. // Where data is put
  214. size_t expected; // Expected amount of data
  215. size_t offset; // Where to put next data
  216. size_t cumulative; // Cumulative data received
  217. // Set some dummy values in the buffer to check
  218. for (size_t i = 0; i < sizeof(inbuff); ++i) {
  219. inbuff[i] = i % 256;
  220. }
  221. // Check that the method will handle various receive sizes.
  222. writeUint16(PACKET_SIZE, inbuff, sizeof(inbuff));
  223. cumulative = 0;
  224. offset = 0;
  225. expected = 0;
  226. outbuff->clear();
  227. bool complete = test.processReceivedData(inbuff, 1, cumulative, offset,
  228. expected, outbuff);
  229. EXPECT_FALSE(complete);
  230. EXPECT_EQ(1, cumulative);
  231. EXPECT_EQ(1, offset);
  232. EXPECT_EQ(0, expected);
  233. EXPECT_EQ(0, outbuff->getLength());
  234. // Now pretend that we've received one more byte.
  235. complete = test.processReceivedData(inbuff, 1, cumulative, offset, expected,
  236. outbuff);
  237. EXPECT_FALSE(complete);
  238. EXPECT_EQ(2, cumulative);
  239. EXPECT_EQ(0, offset);
  240. EXPECT_EQ(PACKET_SIZE, expected);
  241. EXPECT_EQ(0, outbuff->getLength());
  242. // Add another two bytes. However, this time note that we have to offset
  243. // in the input buffer because it is expected that the next chunk of data
  244. // from the connection will be read into the start of the buffer.
  245. complete = test.processReceivedData(inbuff + cumulative, 2, cumulative,
  246. offset, expected, outbuff);
  247. EXPECT_FALSE(complete);
  248. EXPECT_EQ(4, cumulative);
  249. EXPECT_EQ(0, offset);
  250. EXPECT_EQ(PACKET_SIZE, expected);
  251. EXPECT_EQ(2, outbuff->getLength());
  252. const uint8_t* dataptr = static_cast<const uint8_t*>(outbuff->getData());
  253. EXPECT_TRUE(equal(inbuff + 2, inbuff + cumulative, dataptr));
  254. // And add the remaining data. Remember that "inbuff" is "PACKET_SIZE + 2"
  255. // long.
  256. complete = test.processReceivedData(inbuff + cumulative,
  257. PACKET_SIZE + 2 - cumulative,
  258. cumulative, offset, expected, outbuff);
  259. EXPECT_TRUE(complete);
  260. EXPECT_EQ(PACKET_SIZE + 2, cumulative);
  261. EXPECT_EQ(0, offset);
  262. EXPECT_EQ(PACKET_SIZE, expected);
  263. EXPECT_EQ(PACKET_SIZE, outbuff->getLength());
  264. dataptr = static_cast<const uint8_t*>(outbuff->getData());
  265. EXPECT_TRUE(equal(inbuff + 2, inbuff + cumulative, dataptr));
  266. }
  267. // TODO: Need to add a test to check the cancel() method
  268. // Tests the operation of a TCPSocket by opening it, sending an asynchronous
  269. // message to a server, receiving an asynchronous message from the server and
  270. // closing.
  271. TEST(TCPSocket, sequenceTest) {
  272. // Common objects.
  273. IOService service; // Service object for async control
  274. // The client - the TCPSocket being tested
  275. TCPSocket<TCPCallback> client(service);// Socket under test
  276. TCPCallback client_cb("Client"); // Async I/O callback function
  277. TCPEndpoint client_remote_endpoint; // Where client receives message from
  278. OutputBufferPtr client_buffer(new OutputBuffer(128));
  279. // Received data is put here
  280. // The server - with which the client communicates.
  281. IOAddress server_address(SERVER_ADDRESS);
  282. // Address of target server
  283. TCPCallback server_cb("Server"); // Server callback
  284. TCPEndpoint server_endpoint(server_address, SERVER_PORT);
  285. // Endpoint describing server
  286. TCPEndpoint server_remote_endpoint; // Address where server received message from
  287. tcp::socket server_socket(service.get_io_service());
  288. // Socket used for server
  289. // Step 1. Create the connection between the client and the server. Set
  290. // up the server to accept incoming connections and have the client open
  291. // a channel to it.
  292. // Set up server - open socket and queue an accept.
  293. server_cb.queued() = TCPCallback::ACCEPT;
  294. server_cb.called() = TCPCallback::NONE;
  295. server_cb.setCode(42); // Some error
  296. tcp::acceptor acceptor(service.get_io_service(),
  297. tcp::endpoint(tcp::v4(), SERVER_PORT));
  298. acceptor.set_option(tcp::acceptor::reuse_address(true));
  299. acceptor.async_accept(server_socket, server_cb);
  300. // Set up client - connect to the server.
  301. client_cb.queued() = TCPCallback::OPEN;
  302. client_cb.called() = TCPCallback::NONE;
  303. client_cb.setCode(43); // Some error
  304. EXPECT_FALSE(client.isOpenSynchronous());
  305. client.open(&server_endpoint, client_cb);
  306. // Run the open and the accept callback and check that they ran.
  307. service.run_one();
  308. service.run_one();
  309. EXPECT_EQ(TCPCallback::ACCEPT, server_cb.called());
  310. EXPECT_EQ(0, server_cb.getCode());
  311. EXPECT_EQ(TCPCallback::OPEN, client_cb.called());
  312. EXPECT_EQ(0, client_cb.getCode());
  313. // Step 2. Get the client to write to the server asynchronously. The
  314. // server will loop reading the data synchronously.
  315. // Write asynchronously to the server.
  316. client_cb.called() = TCPCallback::NONE;
  317. client_cb.queued() = TCPCallback::WRITE;
  318. client_cb.setCode(143); // Arbitrary number
  319. client_cb.length() = 0;
  320. client.asyncSend(OUTBOUND_DATA, sizeof(OUTBOUND_DATA), &server_endpoint, client_cb);
  321. // Wait for the client callback to complete. (Must do this first on
  322. // Solaris: if we do the synchronous read first, the test hangs.)
  323. service.run_one();
  324. // Synchronously read the data from the server.;
  325. serverRead(server_socket, server_cb);
  326. // Check the client state
  327. EXPECT_EQ(TCPCallback::WRITE, client_cb.called());
  328. EXPECT_EQ(0, client_cb.getCode());
  329. EXPECT_EQ(sizeof(OUTBOUND_DATA) + 2, client_cb.length());
  330. // ... and check what the server received.
  331. EXPECT_EQ(sizeof(OUTBOUND_DATA) + 2, server_cb.cumulative());
  332. EXPECT_TRUE(equal(OUTBOUND_DATA,
  333. (OUTBOUND_DATA + (sizeof(OUTBOUND_DATA) - 1)),
  334. (server_cb.data() + 2)));
  335. // Step 3. Get the server to write all the data asynchronously and have the
  336. // client loop (asynchronously) reading the data. Note that we copy the
  337. // data into the server's internal buffer in order to precede it with a two-
  338. // byte count field.
  339. // Have the server write asynchronously to the client.
  340. server_cb.called() = TCPCallback::NONE;
  341. server_cb.queued() = TCPCallback::WRITE;
  342. server_cb.length() = 0;
  343. server_cb.cumulative() = 0;
  344. writeUint16(sizeof(INBOUND_DATA), server_cb.data(), TCPCallback::MIN_SIZE);
  345. copy(INBOUND_DATA, (INBOUND_DATA + sizeof(INBOUND_DATA) - 1),
  346. (server_cb.data() + 2));
  347. server_socket.async_send(boost::asio::buffer(server_cb.data(),
  348. (sizeof(INBOUND_DATA) + 2)),
  349. server_cb);
  350. // Have the client read asynchronously.
  351. client_cb.called() = TCPCallback::NONE;
  352. client_cb.queued() = TCPCallback::READ;
  353. client_cb.length() = 0;
  354. client_cb.cumulative() = 0;
  355. client_cb.expected() = 0;
  356. client_cb.offset() = 0;
  357. client.asyncReceive(client_cb.data(), TCPCallback::MIN_SIZE,
  358. client_cb.offset(), &client_remote_endpoint,
  359. client_cb);
  360. // Run the callbacks. Several options are possible depending on how ASIO
  361. // is implemented and whether the message gets fragmented:
  362. //
  363. // 1) The send handler may complete immediately, regardess of whether the
  364. // data has been read by the client. (This is the most likely.)
  365. // 2) The send handler may only run after all the data has been read by
  366. // the client. (This could happen if the client's TCP buffers were too
  367. // small so the data was not transferred to the "remote" system until the
  368. // remote buffer has been emptied one or more times.)
  369. // 3) The client handler may be run a number of times to handle the message
  370. // fragments and the server handler may run between calls of the client
  371. // handler.
  372. //
  373. // So loop, running one handler at a time until we are certain that all the
  374. // handlers have run.
  375. bool server_complete = false;
  376. bool client_complete = false;
  377. while (!server_complete || !client_complete) {
  378. service.run_one();
  379. // Has the server run?
  380. if (!server_complete) {
  381. if (server_cb.called() == server_cb.queued()) {
  382. // Yes. Check that the send completed successfully and that
  383. // all the data that was expected to have been sent was in fact
  384. // sent.
  385. EXPECT_EQ(0, server_cb.getCode());
  386. EXPECT_EQ((sizeof(INBOUND_DATA) + 2), server_cb.length());
  387. server_complete = true;
  388. continue;
  389. }
  390. }
  391. if (!client_complete) {
  392. // Client callback must have run. Check that it ran OK.
  393. EXPECT_EQ(TCPCallback::READ, client_cb.called());
  394. EXPECT_EQ(0, client_cb.getCode());
  395. // Check if we need to queue another read, copying the data into
  396. // the output buffer as we do so.
  397. client_complete = client.processReceivedData(client_cb.data(),
  398. client_cb.length(),
  399. client_cb.cumulative(),
  400. client_cb.offset(),
  401. client_cb.expected(),
  402. client_buffer);
  403. // If the data is not complete, queue another read.
  404. if (! client_complete) {
  405. client_cb.called() = TCPCallback::NONE;
  406. client_cb.queued() = TCPCallback::READ;
  407. client_cb.length() = 0;
  408. client.asyncReceive(client_cb.data(), TCPCallback::MIN_SIZE ,
  409. client_cb.offset(), &client_remote_endpoint,
  410. client_cb);
  411. }
  412. }
  413. }
  414. // Both the send and the receive have completed. Check that the received
  415. // is what was sent.
  416. // Check the client state
  417. EXPECT_EQ(TCPCallback::READ, client_cb.called());
  418. EXPECT_EQ(0, client_cb.getCode());
  419. EXPECT_EQ(sizeof(INBOUND_DATA) + 2, client_cb.cumulative());
  420. EXPECT_EQ(sizeof(INBOUND_DATA), client_buffer->getLength());
  421. // ... and check what the server sent.
  422. EXPECT_EQ(TCPCallback::WRITE, server_cb.called());
  423. EXPECT_EQ(0, server_cb.getCode());
  424. EXPECT_EQ(sizeof(INBOUND_DATA) + 2, server_cb.length());
  425. // ... and that what was sent is what was received.
  426. const uint8_t* received = static_cast<const uint8_t*>(client_buffer->getData());
  427. EXPECT_TRUE(equal(INBOUND_DATA, (INBOUND_DATA + (sizeof(INBOUND_DATA) - 1)),
  428. received));
  429. // Close client and server.
  430. EXPECT_NO_THROW(client.close());
  431. EXPECT_NO_THROW(server_socket.close());
  432. }