tcp_socket_unittest.cc 19 KB

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