tcp_socket_unittest.cc 19 KB

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